渲染整体架构
DX11一共有6种Shader:vs、ps、cs、hs、ds、gs
我们通过尾缀来标识是哪种shader,hlsl文件中通过 pragma 来标识shader入口。
一个pass需要写在一个shader中并标识。
Pipeline State 包含blend state、Rasterizer State、Depth Stencil State
Render Pass 包含一趟pass所需的shader(vs、ps、cs、hs、ds、gs,定义可见Shader规范 一节)。这里面村的是 IShader,里头会有这个shader对应的constant buffer以及其他,通过着色器反射来获取到。
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一个变量的值。例如
.SetUniform("xx", value)
material有点类似一个subpassRender Tech 包含 Material、index buffer、vertex buffer、topology、vertex layout,相当于一次渲染
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。
这样子我们渲染的步骤就变成:
遍历render queue的每一个pass
对每个pass而言,获取对应的pipeline,并bind
遍历这个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 类中再写一次做对应。
Last updated