Notifications
Clear all
Topic starter 27/08/2025 11:49 pm
Here's a comprehensive 3D video game engine structure using OpenGL and CUDA, organized with a modular approach for maintainability: ### Folder Structure: ``` game_engine/ ├── src/ │ ├── core/ │ │ ├── engine.cpp │ │ ├── engine.h │ │ ├── window.cpp │ │ ├── window.h │ │ └── input_manager.cpp │ │ └── input_manager.h │ ├── graphics/ │ │ ├── renderer.cpp │ │ ├── renderer.h │ │ ├── shader.cpp │ │ ├── shader.h │ │ ├── mesh.cpp │ │ ├── mesh.h │ │ ├── texture.cpp │ │ ├── texture.h │ │ └── camera.cpp │ │ └── camera.h │ ├── physics/ │ │ ├── physics_engine.cpp │ │ ├── physics_engine.h │ │ ├── rigid_body.cpp │ │ └── rigid_body.h │ ├── cuda/ │ │ ├── cuda_renderer.cu │ │ ├── cuda_renderer.cuh │ │ ├── cuda_physics.cu │ │ └── cuda_physics.cuh │ ├── game_objects/ │ │ ├── game_object.cpp │ │ ├── game_object.h │ │ ├── player.cpp │ │ └── player.h │ ├── utils/ │ │ ├── logger.cpp │ │ └── logger.h │ └── main.cpp ├── assets/ │ ├── shaders/ │ │ ├── vertex.glsl │ │ └── fragment.glsl │ ├── models/ │ └── textures/ ├── libs/ │ ├── glfw/ │ ├── glad/ │ ├── glm/ │ └── assimp/ └── CMakeLists.txt ``` ### Core Engine Components: **src/core/engine.h** ```cpp #ifndef ENGINE_H #define ENGINE_H #include <memory> #include "window.h" #include "input_manager.h" class Engine { public: static std::unique_ptr<Engine> instance; void run(); void initialize(); void update(float deltaTime); void render(); private: bool isRunning = false; Window window; InputManager inputManager; void processInput(float deltaTime); }; #endif // ENGINE_H ``` **src/core/engine.cpp** ```cpp #include "engine.h" #include "../utils/logger.h" std::unique_ptr<Engine> Engine::instance = nullptr; void Engine::run() { initialize(); isRunning = true; while (!window.shouldClose()) { float deltaTime = 0.016f; // ~60fps processInput(deltaTime); update(deltaTime); render(); window.swapBuffers(); window.pollEvents(); } } void Engine::initialize() { Logger::log("Initializing engine..."); window.initialize(); inputManager.initialize(window); Logger::log("Engine initialized successfully!"); } void Engine::update(float deltaTime) { // Game logic updates } void Engine::render() { // OpenGL rendering commands glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void Engine::processInput(float deltaTime) { if (inputManager.isKeyPressed(GLFW_KEY_ESCAPE)) { window.close(); } } ``` **src/core/window.h** ```cpp #ifndef WINDOW_H #define WINDOW_H #include <GL/glew.h> #include <GLFW/glfw3.h> class Window { public: void initialize(); bool shouldClose() const; void swapBuffers(); void pollEvents(); void close(); private: GLFWwindow* window; int width = 1024; int height = 768; }; #endif // WINDOW_H ``` **src/core/window.cpp** ```cpp #include "window.h" #include "../utils/logger.h" void Window::initialize() { if (!glfwInit()) { Logger::log("Failed to initialize GLFW", LogLevel::ERROR); return; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window = glfwCreateWindow(width, height, "Game Engine", nullptr, nullptr); if (!window) { Logger::log("Failed to create GLFW window", LogLevel::ERROR); glfwTerminate(); return; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, [](GLFWwindow*, int width, int height) { glViewport(0, 0, width, height); }); if (glewInit() != GLEW_OK) { Logger::log("Failed to initialize GLEW", LogLevel::ERROR); return; } glEnable(GL_DEPTH_TEST); Logger::log("Window initialized successfully!"); } bool Window::shouldClose() const { return glfwWindowShouldClose(window); } void Window::swapBuffers() { glfwSwapBuffers(window); } void Window::pollEvents() { glfwPollEvents(); } void Window::close() { glfwSetWindowShouldClose(window, true); } ``` **src/graphics/renderer.h** ```cpp #ifndef RENDERER_H #define RENDERER_H #include <memory> #include "shader.h" #include "mesh.h" class Renderer { public: void render(const std::vector<std::shared_ptr<Mesh>>& meshes); void setShader(const std::shared_ptr<Shader>& shader); private: std::shared_ptr<Shader> currentShader; }; #endif // RENDERER_H ``` **src/graphics/renderer.cpp** ```cpp #include "renderer.h" #include <glad/glad.h> void Renderer::render(const std::vector<std::shared_ptr<Mesh>>& meshes) { for (const auto& mesh : meshes) { if (currentShader) { currentShader->use(); mesh->draw(); } } } void Renderer::setShader(const std::shared_ptr<Shader>& shader) { currentShader = shader; } ``` **src/graphics/mesh.h** ```cpp #ifndef MESH_H #define MESH_H #include <vector> #include <glad/glad.h> #include <glm/glm.hpp> struct Vertex { glm::vec3 position; glm::vec3 normal; glm::vec2 texCoords; }; class Mesh { public: Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices); void draw(); private: unsigned int VAO, VBO, EBO; unsigned int vertexCount; unsigned int indexCount; void setupMesh(); }; #endif // MESH_H ``` **src/graphics/mesh.cpp** ```cpp #include "mesh.h" #include <glad/glad.h> Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<unsigned int>& indices) : vertexCount(vertices.size()), indexCount(indices.size()) { setupMesh(); glBindVertexArray(VAO); // Vertex data glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); // Index data glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); // Vertex attributes glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); glEnableVertexAttribArray(1); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoords)); glEnableVertexAttribArray(2); glBindVertexArray(0); } void Mesh::setupMesh() { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); } void Mesh::draw() { glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0); glBindVertexArray(0); } ``` **src/graphics/shader.h** ```cpp #ifndef SHADER_H #define SHADER_H #include <string> #include <unordered_map> #include <glad/glad.h> #include <glm/glm.hpp> class Shader { public: Shader(const std::string& vertexPath, const std::string& fragmentPath); void use(); void setMat4(const std::string &name, const glm::mat4 &mat) const; void setVec3(const std::string &name, const glm::vec3 &value) const; private: unsigned int ID; std::string vertexCode; std::string fragmentCode; void compileShaders(); }; #endif // SHADER_H ``` **src/graphics/shader.cpp** ```cpp #include "shader.h" #include <fstream> #include <sstream> #include "../utils/logger.h" Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { std::ifstream vShaderFile(vertexPath); std::ifstream fShaderFile(fragmentPath); std::stringstream vShaderStream, fShaderStream; vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); compileShaders(); } void Shader::compileShaders() { const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); unsigned int vertex, fragment; int success; char infoLog[512]; // Vertex shader compilation vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vShaderCode, NULL); glCompileShader(vertex); glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertex, 512, NULL, infoLog); Logger::log("Vertex shader compilation failed: " + std::string(infoLog), LogLevel::ERROR); } // Fragment shader compilation fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fShaderCode, NULL); glCompileShader(fragment); glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragment, 512, NULL, infoLog); Logger::log("Fragment shader compilation failed: " + std::string(infoLog), LogLevel::ERROR); } // Shader program ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); glLinkProgram(ID); glGetProgramiv(ID, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(ID, 512, NULL, infoLog); Logger::log("Shader program linking failed: " + std::string(infoLog), LogLevel::ERROR); } glDeleteShader(vertex); glDeleteShader(fragment); } void Shader::use() { glUseProgram(ID); } void Shader::setMat4(const std::string &name, const glm::mat4 &mat) const { glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } void Shader::setVec3(const std::string &name, const glm::vec3 &value) const { glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } ``` ### CUDA Components: **src/cuda/cuda_renderer.cuh** ```cuda #ifndef CUDA_RENDERER_CUH #define CUDA_RENDERER_CUH #include <cuda_runtime.h> #include <device_launch_parameters.h> // Structure for GPU vertex data struct GPUVertex { float x, y, z; float nx, ny, nz; float u, v; }; __global__ void cudaRenderKernel(GPUVertex* vertices, int count); #endif // CUDA_RENDERER_CUH ``` **src/cuda/cuda_renderer.cu** ```cuda #include "cuda_renderer.cuh" #include <stdio.h> __global__ void cudaRenderKernel(GPUVertex* vertices, int count) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < count) { // Simple vertex transformation example vertices[idx].x += 0.01f; vertices[idx].y += 0.01f; } } void launchCudaRender(GPUVertex* d_vertices, int count) { int threadsPerBlock = 256; int blocksPerGrid = (count + threadsPerBlock - 1) / threadsPerBlock; cudaRenderKernel<<<blocksPerGrid, threadsPerBlock>>>(d_vertices, count); cudaDeviceSynchronize(); } ``` **src/cuda/cuda_physics.cuh** ```cuda #ifndef CUDA_PHYSICS_CUH #define CUDA_PHYSICS_CUH #include <cuda_runtime.h> struct RigidBody { float x, y, z; float vx, vy, vz; float mass; bool active; }; __global__ void cudaPhysicsKernel(RigidBody* bodies, int count, float deltaTime); #endif // CUDA_PHYSICS_CUH ``` **src/cuda/cuda_physics.cu** ```cuda #include "cuda_physics.cuh" #include <stdio.h> __global__ void cudaPhysicsKernel(RigidBody* bodies, int count, float deltaTime) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < count && bodies[idx].active) { // Simple physics simulation bodies[idx].x += bodies[idx].vx * deltaTime; bodies[idx].y += bodies[idx].vy * deltaTime; bodies[idx].z += bodies[idx].vz * deltaTime; // Gravity effect bodies[idx].vy -= 9.81f * deltaTime; } } void launchCudaPhysics(RigidBody* d_bodies, int count, float deltaTime) { int threadsPerBlock = 256; int blocksPerGrid = (count + threadsPerBlock - 1) / threadsPerBlock; cudaPhysicsKernel<<<blocksPerGrid, threadsPerBlock>>>(d_bodies, count, deltaTime); cudaDeviceSynchronize(); } ``` ### Main Application: **src/main.cpp** ```cpp #include "core/engine.h" #include <memory> int main() { auto engine = std::make_unique<Engine>(); engine->run(); return 0; } ``` ### CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.10) project(GameEngine) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Find packages find_package(glfw3 REQUIRED) find_package(GLEW REQUIRED) find_package(glm REQUIRED) find_package(OpenMP REQUIRED) find_package(CUDA REQUIRED) # Add CUDA support enable_language(CUDA) # Include directories include_directories(${PROJECT_SOURCE_DIR}/src) include_directories(${GLEW_INCLUDE_DIRS}) include_directories(${GLFW_INCLUDE_DIRS}) include_directories(${GLM_INCLUDE_DIRS}) # Source files set(SOURCES src/main.cpp src/core/engine.cpp src/core/window.cpp src/core/input_manager.cpp src/graphics/renderer.cpp src/graphics/shader.cpp src/graphics/mesh.cpp src/graphics/texture.cpp src/graphics/camera.cpp src/physics/physics_engine.cpp src/physics/rigid_body.cpp src/game_objects/game_object.cpp src/game_objects/player.cpp src/utils/logger.cpp ) # CUDA files set(CUDA_SOURCES src/cuda/cuda_renderer.cu src/cuda/cuda_physics.cu ) # Create executable add_executable(${PROJECT_NAME} ${SOURCES} ${CUDA_SOURCES}) # Link libraries target_link_libraries(${PROJECT_NAME} glfw GLEW::GLEW OpenMP::OpenMP_CXX ${CUDA_LIBRARIES} ) # Set CUDA properties set_property(TARGET ${PROJECT_NAME} PROPERTY CUDA_SEPARABLE_COMPILATION ON) ``` ### Key Features: 1. **Modular Architecture**: Separated core engine, graphics, physics, and utilities 2. **OpenGL Integration**: Full OpenGL rendering pipeline with shaders 3. **CUDA Acceleration**: Physics and rendering acceleration through CUDA 4. **Resource Management**: Proper handling of vertex buffers, textures, and shaders 5. **Extensible Design**: Easy to add new components and features ### Building Instructions: 1. Install dependencies: GLFW, GLEW, GLM, CUDA toolkit 2. Create build directory: `mkdir build && cd build` 3. Configure with CMake: `cmake ..` 4. Build: `make -j$(nproc)` This structure provides a solid foundation for a 3D game engine that can leverage both OpenGL for rendering and CUDA for physics calculations, offering good performance and scalability.
This topic was modified 2 weeks ago by josh