绘制
Note
写在前面:
对于后续提到的数据,尽管c++支持在类体中直接初始化,但直接在类体初始化会导致阅读和管理困难,且DX12项目中的初始化往往依赖D3D12提供的接口,在极端情况下可能存在相关接口还没完成初始化的时序问题。
因此,在通常实践中,应该将初始化语法写在具体的方法内,并统一调用。譬如,下文提到的顶点与输入布局描述就可以在BuildPSO方法中初始化。
Note
对于任何代码中创建的任何数据和对象,最初都只存在于CPU中,为了使GPU能够访问和处理这些数据,需要手动将数据送到GPU中,即在初始化渲染器时大段的代码都是在执行”创建数据-创建上传缓冲区和资源缓冲区-拷贝数据到上传缓冲区-从上传缓冲区拷贝到资源缓冲区“这一过程。
约定以下命名:
上传缓冲区/上传堆(upload Buffer):CPU无法将资源直接送进GPU用于计算的区域,只能将它暂存在RAM或GPU划分出来用于和CPU通讯的区域内。称这些区域为上传缓冲区/上传堆,是CPU可读写、GPU可读但速度较慢的区域。
资源缓冲区/默认堆(Default Buffer):GPU内部存储资源和计算的区域,按照对应的资源进行进一步的命名划分,如顶点缓冲区、视图缓冲区,其本质是连续内存的二进制数据,需要根据描述符来确定具体的读取方式。
其中,常量缓冲区是例外,由于每帧都有大量的变化,通常直接写在上传缓冲区内。
顶点与输入布局描述
1. 定义顶点结构体,声明顶点中存储的具体数据。譬如,一个包含位置和颜色信息的顶点以如下方式进行定义:
顶点结构体和顶点类型绑定,有多少顶点类型就需要创建多少顶点结构体。
2. 为每个顶点结构体创建D3D12_INPUT_ELEMENT_DESC数组,用于描述顶点结构体中每个元素。
以\(1.\)中的Vertex为例,创建D3D12_INPUT_ELEMENT_DESC的语句如下:
D3D12_INPUT_ELEMENT_DESC包含\(7\)个元素,每个元素有固定含义,描述如下:
D3D12_INPUT_ELEMENT_DESC结构体定义及含义
-
SemanticName:语义名,一个和元素相关联的特定字符串,表明该元素的用途。语义名需要和顶点着色器输入签名(参数列表)保持一致,因此通常会使用规范化命名,常用语义名包括
"POSITION"、"COLOR"、"NORMAL"、"TEXCOORD"等。
-
SemanticIndex:语义索引,如果一个顶点结构体中存在多个相同语义的的元素,则需要通过语义索引区分它们。这样做能在区分相同语义的元素的同时不引进新的语义名,默认从0开始。
Format:数据格式,即顶点结构体中对应的元素的数据格式,但这里不写在顶点结构体中声明元素时的类型名,应该写DXGI_FORMAT枚举。
InputSlot:输入槽索引,指定传递元素所以所用的输入槽(顶点缓冲区),值范围为0-15,只有一个时默认设为0。
-
AlignedByteOffset:对齐字节偏移,值为顶点结构体中这个元素前所有元素占用的字节总和。如果是首个元素的话,值为0。
-
InputSlotClass:输入分类,表明数据按顶点还是实例读取,有以下两个选项:D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA:每个顶点读取一次数据。最常用的选项,画普通物体时使用。D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA:用于实例化渲染。
InstanceDataStepRate:实例步进速率,默认设为0,开启实例化渲染时设为1。
3. 声明D3D12_INPUT_LAYOUT_DESC对象,作为D3D12_INPUT_ELEMENT_DESC的清单,并将D3D12_INPUT_ELEMENT_DESC数组绑定到该对象上。
以\(1.\)和\(2.\)声明的顶点结构体为例,该步骤的语句如下:
其中,data()方法是标准STL容器提供的方法,返回指向容器首个元素的原始指针
Note
D3D12_INPUT_LAYOUT_DESC对象是一个过程对象,仅用于初始化渲染管线,因此不必将其声明为类的成员。
顶点缓冲区
1. 使用上文中的顶点类型创建顶点数组。
vertices
2. 根据顶点数组的大小计算缓冲区大小,创建上传堆和默认堆