Skip to content

Repository files navigation

介绍

基于OpenGL4.6实现的渲染引擎

项目源码编码为UTF8

待办

  • 设计项目结构
  • 修改相机控制方案
  • 改用SDL3管理窗口
  • 数据加载和管理
  • 场景管理,以model为单位
  • 资源管理方式采用全局ID和name
  • 统一顶点属性格式,设置固定格式shader
  • 绘制网格
  • 添加所有纹理
  • 添加光照
  • skyBox(6面图和hdr)
  • 反射环境光
  • 实现PBR材质
  • PBR的IBL
  • 日志 spdlog模块
  • imgui模块
  • 阴影
  • HDR
  • 后处理(泛光)
  • 调整结构
  • 光追渲染管线
  • 资源加载异步化

效果展示

image-20251007231700576

功能介绍

  1. wasdqe操作相机
  2. 鼠标拖拽旋转相机

项目结构

引擎模块

[ Application / Game Layer ]
   ├─ GameLogic / Editor / Script
   └─ 使用 SceneManager 创建对象、控制 RenderManager 渲染
          │
          ▼
[ Engine Layer ]
   ├─ Engine
   │    ├─ 初始化/更新/销毁各模块
   │    └─ 主循环(Update → Render)
   │
   ├─ SceneManager
   │    ├─ SceneObject / Entity
   │    │    ├─ Transform (位置/旋转/缩放)
   │    │    ├─ MeshRef → ResourceManager.Mesh
   │    │    └─ MaterialRef → ResourceManager.Material
   │    ├─ Camera
   │    └─ Light
   │
   ├─ ResourceManager
   │    ├─ Mesh (顶点/索引/法线/UV)
   │    ├─ Material (Shader + 参数)
   │    └─ Texture
   │
   ├─ RenderManager
   │    ├─ 遍历 SceneObjects
   │    ├─ 构建 DrawCall / RenderCommand
   │    └─ 提交 CommandList 到 RHI
   │
   └─ Display/WindowManager
        ├─ 窗口创建/销毁
        └─ 输入事件处理
          │
          ▼
[ RHI Layer ]
   ├─ Buffer (Vertex/Index/Uniform)
   ├─ Texture (GPU纹理)
   ├─ Shader
   ├─ Pipeline (绑定Shader + RenderState + VertexLayout)
   └─ CommandList (绘制命令)
          │
          ▼
[ Platform Layer ]
   ├─ OS API (Win32, Cocoa, X11)
   └─ GPU API (OpenGL, Vulkan, DX12, Metal)

数据流示意图

Application/Game Layer
        ↓
   Engine Layer
   ├── SceneManager → 遍历对象
   ├── ResourceManager → 提供 Mesh/Material/Texture 数据
   ├── RenderManager → 构建 DrawCalls
        ↓
    RHI Layer
   ├── Buffer / Texture / Shader / Pipeline
   └── CommandList → GPU 指令
        ↓
   Platform Layer
   ├── OS API → 窗口、输入
   └── GPU API → 实际提交渲染

简化数据流

ResourceManager (CPU 数据)
          │
   SceneObject 引用 CPU 数据
          │
    RenderManager / MeshGPU
          │ 调用
          ▼
   RHI (Buffer/Texture/Shader)
          │
       GPU API 提交
          ▼
       GPU 渲染

仓库结构

MyRenderingEngine
|-- resources
|   |-- PointCloud          # 点云文件
|   |-- scenes              # Scene description files in JSON format
|   |-- shaders
|   |   |-- computeShaders  # Compute shaders for clustered forward
|   |   |-- OldShaders      # Shaders not currently in use
|   |   `-- currentShaders  # Shaders for the current rendering pipeline
|   `-- skyboxes            # Skyboxes in either cubemap or equirectangular map form
|-- build                   # CMake compile  
|-- include                 # Project header files
|-- libs                    # Check dependencies section for descriptions & links
|   |-- ASSIMP               
|   |-- Dear imgui           
|   |-- Glad 
|   |-- Json c++            
|   |-- GLI 
|   |-- stb_image 
|   `-- SDL2 
|-- modules                 # CMake lib setup scripts
|-- src                     # C++ implementation files
`-- CMakeLists.txt          # CMake build script

渲染流程分层

RenderPipeline
一套固定的渲染状态 + 着色器组合(比如 ForwardPipeline、LightingPipeline)。
可以理解为“一个小模块,定义了怎么画”。

RenderPass
定义“画在哪里”,绑定哪些 framebuffer/attachments(颜色、深度、G-buffer 等)。
一个 pass 通常会调用若干个 pipeline。
例如:Deferred 的 GeometryPass + LightingPass。

RenderGraph / Renderer(渲染流程)
定义多个 pass 的执行顺序和依赖关系(比如:几何 → 光照 → 后处理 → UI)。
知道哪些 Pass 要先执行、哪些 Buffer 要作为输入输出。
本质上是一个 调度器。

RenderManager / Engine 层
站在引擎最上层,负责管理场景、相机、资源加载。
它不直接关心每个 pass 怎么画,只负责驱动 Renderer 去渲染一帧。

RenderManager(顶层)
   |
   └── Renderer(渲染器,FrameGraph 调度)
          |
          ├── RenderPass(一个个阶段)
          │        └── 调用对应的 RenderPipeline
          │
          └── FrameBuffer / Resource 管理


Pipeline:具体绘制方法
Pass:一个渲染阶段
Renderer(或 RenderGraph):管理所有 Pass 的执行顺序
RenderManager:顶层接口,调度 Renderer,但不关心细节

渲染引擎分层


[ Application/Game Layer ]

   - 游戏逻辑 / 编辑器 / 脚本

[ Engine Layer ]

   - Engine (统一入口)
   - SceneManager (场景管理:对象、相机、灯光)
   - RenderManager (渲染调度:负责把场景绘制出来)
   - ResourceManager (资源管理:模型、材质、纹理)
   - Display/WindowManager (窗口系统 / 输入输出)

[ Render Hardware Interface (RHI) Layer ]

   - Buffer / Texture / Shader / Pipeline / CommandList

[ Platform Layer ]

   - OS API (Win32, Cocoa, X11)
   - GPU API (OpenGL, Vulkan, DX12, Metal)

渲染调用链


// 渲染调度
void RenderManager::render(SceneManager& sceneManager) {
    Scene& scene = sceneManager.getActiveScene();
    Camera& camera = scene.getCamera();

    renderScene(scene,camera);
}


void RenderManager::renderScene(scene,camera){
    useShaderProgram();
    for (auto& model : passes) {
        renderModel(model, camera);
    }
}
void RenderManager::renderModel(model,camera){
    vector<int> meshids= model.getmeshes();
    vector<int> textureids= model.getmeshes();
    setMat4("model",model.getModelMatrix());
    for(int id:meshids){
        renderMesh(id);
    }

}
void RenderManager::renderMesh(meshid,){
    meshgl = resourcemanager.getmeshgl(meshid)
    
    bindMesh()

    draw()
}

RenderPass(RHI);

Renderer,RenderPipeline,RenderPass的关系

Renderer (对外接口层)
│
├── ForwardRenderer
│     └── 使用 ForwardRenderPipeline
│             ├── ShadowPass
│             ├── GeometryPass
│             └── LightingPass
│
├── DeferredRenderer
│     └── 使用 DeferredRenderPipeline
│             ├── GBufferPass
│             ├── LightingPass
│             └── PostProcessPass
│
└── PathTracingRenderer
      └── 使用 PathTracingPipeline
              └── RayTracingPass

渲染调用流程

GameLoop
  → RenderEngine.render()
    → RenderManager.render(scene)
      → Renderer.render(scene)
        → RenderPass.execute(scene)
          → drawcall

资源组织形式

与Assimp库类似
scene
|---Models
 	|---Meshs
 		|---vertices
 		|---indices
 		|---textures(texture的id)

RenderEngine vs RenderManager 的职责划分

RenderEngine(引擎核心)

作为全局的调度者,负责:

初始化图形 API(OpenGL / Vulkan / DX12)

创建/销毁窗口和上下文

管理 RenderManager / SceneManager / ResourceManager

驱动整个渲染帧循环(update → render → present)

它不直接管具体的绘制细节,只是调用 RenderManager 去执行渲染。

RenderManager(渲染子系统管理器)

负责真正的绘制流程:

从 Scene 中获取对象(ModelObject、LightObject、Camera)

组织渲染队列(比如按材质/透明度/距离排序)

上传数据到 GPU(Mesh VBO、Texture、UBO 等)

调用底层 API(glDraw*/vkCmdDraw 等)

可细分职责:

渲染准备阶段:清理缓冲区、设置 viewport

遍历场景对象:收集需要绘制的模型和光源

执行绘制:绑定 shader/program → 设置 uniform → draw call

后处理:bloom、shadow、HDR、tone mapping 等

模块职责划分

  • RenderEngine(引擎层)
  • InputManager
    • 交互管理,接收输入信号
  • RenderManager
    • 渲染管理,负责渲染场景,管理所有渲染所需资源和方法
  • Manager类
    • 总的来说Manager是一个资源缓存
    • 持有同类资源的唯一副本,管理资源的生命周期(持有资源,使用共享指针)
    • 临时持有资源(使用裸指针)
    • 负责创建/加载资源,并保证同类资源的唯一性
    • 提供访问资源的接口(返回资源引用)
    • 资源索引方式(id,relativePath,name)
      • relativePath防止资源重复加载
      • name并非唯一标识符,但是目前没有管理name对应多个资源的情况,如果出现同名资源将会替换原来的资源
  • GPU Resource Manager
    • GPU 资源缓存
    • 保存所有 GPU 资源的句柄(Buffer、Texture、Shader)
    • GPU资源和对应的CPU资源采用相同ID管理(确保不会重复加载资源)
  • CPU Resource Manager(CPU 资源)
    • 提供多种查找方式(name,path(保证资源唯一性),id(唯一标识符))
  • Scene Manager
    • 场景
  • SceneObject 可渲染对象
    • ModelObject
      • 持有绘制所需相关资源Id(meshid,textureid)
      • 有自己的transform属性
    • Model,Scene等组成部分均不实现draw函数,只是资源和资源状态的集合
    • 所有对象都只存相关资源id,资源访问通过resourcemanager实现,绘制通过rendermanager实现
  • GPU API 抽象(RHI)

shader切换流程

1. 开始渲染帧
2. 绑定Shader A → 渲染3D模型(处理光照、材质)
3. 解绑Shader A → 绑定Shader B → 渲染UI元素(简单正交投影)
4. 解绑Shader B → 绑定Shader C → 渲染粒子效果(加随机运动逻辑)
5. 解绑Shader C → 绑定Shader D → 执行后期处理(全屏模糊)
6. 结束渲染帧

简单渲染流程概览

// 假设已编译链接好三个Shader程序
GLuint modelShader = ...;   // 3D模型Shader
GLuint uiShader = ...;      // UI Shader
GLuint particleShader = ...;// 粒子Shader

// 渲染3D模型
glUseProgram(modelShader);  // 切换到模型Shader
glBindVertexArray(modelVAO);
glDrawElements(GL_TRIANGLES, ...);

// 渲染UI
glUseProgram(uiShader);     // 切换到UI Shader
glBindVertexArray(uiVAO);
glDrawArrays(GL_TRIANGLES, ...);

// 渲染粒子
glUseProgram(particleShader);  // 切换到粒子Shader
glBindVertexArray(particleVAO);
glDrawArraysInstanced(GL_TRIANGLES, ...);

相关类关系

SceneManager
   └── Scene
         ├── Camera
         ├── Object[]
         └── Light[]

RenderManager
   └── Renderer[]
         └── RenderPipeline
               └── RenderPass[]
                      └── 调用 RenderContext (shader, fbo, state)

RenderContext
   ├── GPU state (blend, depth, cull)
   ├── Current shader
   ├── Current framebuffer
   └── Resource bindings

ShaderManager工作流程

ShaderManager
 └── ShaderProgram("Phong")
      ├── VertexShader
      └── FragmentShader
 └── ShaderProgram("ShadowMap")
      ├── VertexShader
      └── FragmentShader
 └── ShaderProgram("ComputeParticles")
      └── ComputeShader

manager类的职责

Manager 不负责对象的构造,而是负责:

维护对象的生命周期(注册、引用计数、释放)

提供检索、查找、缓存复用等功能

提供统一的接口来访问已有资源

ShaderManager的职责,不同的场景或者需求可能需要不同的PipelineState,shadermanager主要用于防止重复编译相同的shader,而不是说统一管理shader,shader在PipelineState中高度定制化

可优化

  1. shader当前采用固定格式

可用方案:多套着色器,按需切换

为不同顶点格式的模型写不同的着色器。 比如: Shader_PosTex 处理只有位置+UV 的模型。 Shader_PosNormal 处理位置+法线的模型。 Shader_Full 处理位置+法线+UV+切线的模型。 渲染时,根据模型的顶点格式选择对应的 Shader。 优点:更高效,显存占用少。 缺点:Shader 数量爆炸,管理起来麻烦。

一个shader对应多种顶点格式 通过条件判断决定是否使用某些属性。 例如: layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; // 可选 layout (location = 2) in vec2 aTexCoord; // 可选

uniform bool useNormal; uniform bool useTexcoord;

void main() { if (useNormal) { ... } if (useTexcoord) { ... } } 加载模型时,如果模型没有某个属性 → 在 VAO 里给这个 attribute 禁用 (glDisableVertexAttribArray)。 优点:只需一套 Shader,灵活。 缺点:Shader 逻辑复杂,可能有分支开销。

  1. 当前使用全局唯一ID管理资源

可以考虑对象池 + Handle (index + generation) 的方式管理资源

  1. 当前模式为单线程
  2. 当前渲染管线为Forward(不支持透明物体)
  3. 当前未实现灯光管理
  4. 当前DrawCall模式为逐个对象绘制,可以考虑用Indirect Drawing的基本思路 OpenGL 提供了一种方式:把绘制命令本身(例如 indexCount、instanceCount、baseIndex、baseVertex、baseInstance 等)放进 GPU Buffer(GL_DRAW_INDIRECT_BUFFER), 然后用一次 API 调用,让 GPU 批量执行这些命令。 也就是说: 以前:CPU 多次调用 glDrawElements,把参数从 CPU 传给 GPU。 现在:CPU 一次调用 glMultiDrawElementsIndirect,GPU 从 buffer 中自己读出所有 draw 参数。
  5. 当前未实现后处理
  6. 当前未实现实例化渲染

CPU资源销毁时机

GPU资源销毁时机

skybox支持HDR格式

参考

HybridRenderingEngine

Angelo1211/HybridRenderingEngine: Clustered Forward/Deferred renderer with Physically Based Shading, Image Based Lighting and a whole lot of OpenGL.

C++实现的渲染器

Home - Playing with code

RayTracing

0xCCCCCCCCC/Ray_Tracing_CPU

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages