Forum

Notifications
Clear all

OpenGL 3D Video Game Engine with Nvidia CUDA

1 Posts
1 Users
0 Reactions
12 Views
 josh
(@josh)
Member Admin
Joined: 2 months ago
Posts: 510
Topic starter  
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

   
Quote
Share: