HEngine
  • 引擎编译
  • 未来工作
  • 使用文档
    • 代码规范
    • Shader规范
    • config 配置
  • Python脚本系统
    • 技术分析
    • 使用api
  • Cpp脚本系统
    • 技术分析
  • 技术文档 & 心得体会
    • 数学
      • 坐标系、UV与深度范围
      • 行主序 与 列主序
    • 路径管理
    • 构建系统
    • 自定义资源格式
    • UI
      • undo/redo
      • 分辨率处理
    • ECS 系统
    • 插件系统
    • 数学库
    • Ref Counted
    • 音频
    • ChatGPT
    • Mesh、Vertex 等组织关系
    • 编辑器热更新方案
    • Profile
    • NLP
    • RenderDoc
    • CodeGen与反射系统
    • 安装包
    • 物理引擎
      • PhysX集成
      • Bullet集成
    • 动画
  • 图形后端
    • 坐标系差异
    • Feature差异
    • RHI 封装
    • Shader与Constant Buffer
    • DX12
    • Vulkan
    • Render Graph
    • 渲染整体架构
  • 图形Feature
    • 毛发
    • 鼠标拾取
    • 实例化渲染
  • Shader
    • Shader 交叉编译
    • Shader Toy
    • Shader 热更新
    • PBR
  • 打包
    • 打包
  • Bug 记录 & 解决过程
    • 闪退记录汇总
    • 导入图片显示混乱
    • D3D下glfw+imgui失效
  • 其他资料
    • 总结集合
Powered by GitBook
On this page
  • 渲染流程
  • deferred context 与 immediate context
  1. 图形后端

渲染整体架构

DX11一共有6种Shader:vs、ps、cs、hs、ds、gs

我们通过尾缀来标识是哪种shader,hlsl文件中通过 pragma 来标识shader入口。

一个pass需要写在一个shader中并标识。

  1. Pipeline State 包含blend state、Rasterizer State、Depth Stencil State

  2. Render Pass 包含一趟pass所需的shader(vs、ps、cs、hs、ds、gs,定义可见Shader规范 一节)。这里面村的是 IShader,里头会有这个shader对应的constant buffer以及其他,通过着色器反射来获取到。

  3. Material: 包含 Pipeline State 与 Render Pass,并且可以选择 Type(Default即默认的PBR、BaseLit或者是后处理),同时可以对 Pipeline State 进行设置。 选择BaseLit或者后处理的时候则可以 add shader,例如 mat.AddShader("BasePBR"),此时会在CACHE中寻找所有BasePBR.xx,这里XX可以是上面六种尾缀的一种,此时即会去重新构造 Render Pass。 添加进来后会通过着色器反射,把所有信息存在mat中(实际上在 Render Pass 的每个 IShader 里),对应建立常量缓冲区。mat可以set一个变量的值。例如 mat.SetUniform("xx", value) material有点类似一个subpass

  4. Render Tech 包含 Material、index buffer、vertex buffer、topology、vertex layout,相当于一次渲染

  5. Render Pipeline 包含 Render Tech, Frame Buffer

一次渲染应该是以 Render Pipeline 为单位,先绑定 Frame Buffer,再去遍历 Render Tech,每个 Render Tech 的渲染绑定 Material(绑定里面的 State 与 Shader),再去绑定 index buffer、vertex buffer、topology、vertex layout 等。

后续应该接着考虑 Forward、Defferred 等管线的设置。

渲染流程

我们希望逐 pipeline 来进行,而不是遍历mesh每遇到一种材质再绑定一个pipeline。逐pipeline来进行就避免了冗余的绑定,提升了效率。

为此我们需要在反序列化场景的时候(以及更改mesh的材质的时候)去把mesh提交到render queue里面,render queue里面是一个pass到submesh的一个对应。而每个pass目前就对应一条pipeline。

这样子我们渲染的步骤就变成:

  1. 遍历render queue的每一个pass

  2. 对每个pass而言,获取对应的pipeline,并bind

  3. 遍历这个pass对应的所有submesh,渲染submesh

并且我们日后做剔除以及半透明渲染的时候,也可以在对应render queue做submesh的增删与新建render queue。

deferred context 与 immediate context

现代图形api无疑是deferred context的,而在 d3d11 中,也有deferred context的模式,他最终其实还是要提交到immediate context去执行。但是,deferred context往往是线程安全的,我们一般会提交命令到commandlist上,这只是记录下来你的命令,等到真正execute的时候才会真正提交到gpu去执行。因此我们可以多线程地去记录(encode)我们的命令,例如每个线程一个commandlist,最终执行的时候再一并提交。

但是immediate context也有好处:无脑,方便,debug简单,兼容只有immediate context的OpenGL。我们目前要快速堆效果达到一个成熟的可以做游戏的引擎,因此我们直接使用immediate context去封装dx11和OpenGL。

这种模式下我们可以灵活地封装成一个bind函数,用来绑定所需的各种东西,主要是:shader、常量缓冲区、顶点layout(仅dx11,ogl是要先绑定到vertex array里头再去指定)、PrimitiveTopology、vertex buffer与index buffer。全部绑定好后再直接用 Draw 或 DrawIndexed 方法渲染即可。

因此对于各种方法我们可以统一地封装到 RenderCommand 类中。这里我们希望这个类的方法全部都是静态方法,这样调用方便,因此我们需要额外弄个类 RendererAPI 类,相同的方法在 RendererAPI 类中再写一次做对应。

PreviousRender GraphNext毛发

Last updated 1 year ago