开发者网络

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 78|回复: 1

DX12游戏开发实战读书笔记 第六章 绘制几何体

[复制链接]

2

主题

3

帖子

7

积分

新手上路

Rank: 1

积分
7
发表于 2022-11-27 13:47:26 | 显示全部楼层 |阅读模式
本章开始演示了一个完整的绘制出一个Cube的程序。 运行效果为:



例程运行结果

与DX11或OpenGL相比,DX12在绘制之前的必要代码要多得多,这主要是因为将大量的状态切换显式交给了应用开发者,从而支持更高的运行时性能。
幸运的是,本书封装了重复而必要的Device创建、命令列表初始化、渲染视图创建、资源创建等功能[可参见第4章],而允许我们仅需要重写必要的Update、Draw、PSO创建、View创建等。
而要绘制一个几何体,我们需要:
指定顶点与输入布局

输入布局用于描述我们传递到GPU的每个顶点对应的结构体的属性。这些顶点在Vertex Shader阶段被逐个读取并处理,而从CPU到GPU的数据递交中,并没有属性名与属性类型的传递,因此我们必须显式在CPU中通过InputLayout结构体指定顶点的属性,并在Vertex Shader中声明属性与CPU严格一致的结构体。

  • 在初级阶段,我们仅需关注属性的格式、在结构体中的偏移、语义

    • 语义用于协助开发者的理解,且与Vertex Shader中的对应结构体中的属性语义严格一致




D3D12程序中声明顶点输入布局



在shader中与上面的输入布局中的偏移顺序、格式、语义严格对应的结构体

编写编译着色器

着色器的编写语言为hlsl,在本章的示例代码中,并不复杂。



color.hlsl

在本书中,所有Vertex Shader阶段对应的Shader的入口均为VS,相应的,Pixel Shader阶段对应的Shader的入口则为PS。
我们可以发现,所有结构体中的变量都需要指定语义,而以SV_开头的语义表明其为DX系统语义

  • SV_POSITION指顶点经过投影变换后的坐标,其将在光栅化阶段被变换到屏幕中的实际像素位置,PS接受的结构体必须声明了该语义
  • SV_Target指像素颜色,其输出结果将根据我们指定的混合状态与现有颜色缓冲中的同像素混合,PS必须返回该语义
本章中的VS仅仅将输入顶点变换到了投影空间,并将颜色传递到下一阶段;而PS则是将颜色输出到了屏幕中

  • 矩阵变换的数学原理可以参看本书第三章与第五章;如果仅仅需要使用,则简单记住mul方法即可
在真正将Shader传递到GPU之前,我们需要先将shader文件编译为GPU可执行的汇编语言。我们可以直接调用本书封装好的CompileShader方法来进行编译。
声明根参数

观察上面的shader代码,我们可以发现,我们声明了一个cbuffer类型的结构体,且其后面跟随了register(b0)。
而这就是根常量(根参数, root parameter的一种),其描述声明在根签名中,并在运行时动态绑定到实际的根常量,我们将在第7章对其进行详细说明。
指定光栅器状态

我们知道,图形流水线中,位于GPU的阶段分为可编程阶段与可配置阶段两种。可编程阶段我们通过shader代码指定逻辑,而可配置阶段,我们则可以通过该阶段对应的结构体指定该阶段的行为逻辑。
某些可配置的结构体严格意义上并非对应了实际的阶段,但我们为了对其进行配置,抽象出了虚拟的阶段。
一些常见的可配置阶段包括

  • Rasterizer State

    • 指明光栅化时的逻辑,主要有1. 渲染时是否填充内部区域,还是仅仅渲染边框 2. 三角形剔除规则(正面/反面/不剔除) 3. 我们认为顶点顺序为顺时针的三角面才是正面,还是相反

  • DepthStencil State

    • 指明深度与模板测试的方法与通过时的执行方法,本章未使用

  • Blend State

    • 指明多个映射到同一位置的像素颜色之间的混合方式,本章不需要特别指明

创建流水线状态对象

现代图形API普遍将渲染状态的维护显式暴露给了开发者,从而让开发者明确知晓一个命令的开销、减少API乃至硬件猜测并准备一个指令所需要的后台开销,以及通过预先声明所有需要的PSO的方式来允许编译时、运行时优化。
正如其名,流水线状态对象就是一个状态,其指定了本状态中的所有不可变化的属性,这些属性包括了可编程阶段对应的shader、可配置阶段的配置状态、渲染目标的数量与视图、输入顶点的布局、输入图元的拓扑、深度对象的视图、MSAA、Depth/Stencil状态、根签名的视图等。

  • 需要注意的是,渲染目标、根签名等均只需要指定视图,而不需要直接指定实际的资源;这允许我们的一个状态机不会因为具体资源的切换直接变更。
在创建流水线状态对象(Pipeline State Object, PSO)时,我们需要显示定义该状态的所有属性,然后调用相应的创建方法。



创建PSO

创建必要资源

PSO的创建与绘制所需资源的创建并没有严格的先后顺序要求。唯一需要注意的是需要绑定到流水线的资源的格式应当与流水线状态对象中声明的对应的资源视图相同。
在本章中,我们需要创建的仅有顶点们,顶点的索引们,以及一个包含了变换矩阵的根常量。
根常量我们等到第7章中再详细介绍,而顶点的视图我们在输入布局中进行了描述。



创建输入顶点

绑定输入、参数

在资源与PSO均准备好后,我们即可绑定输入的顶点与根参数。在本章中,我们仅关注绑定顶点与索引的两个命令即可。
我们前面说过,顶点是Vertex Shader中处理的单位,因此其是必须指定的。

  • 当指定时,我们要注意,应当指定我们的输入图元的拓扑(在PSO中仅仅声明了是三角形,但并未说明是三角形列表,还是三角形带)
而索引是为了复用顶点、更好拓扑而提供的辅助结构体(我们可以很容易发现,顶点仅仅为16bit,而一个顶点则是32*7 = 224bit)。



指定输入顶点与索引

准备命令列表,指定绘制目标,进行绘制调用

命令列表用于记录向GPU提交的命令们,在准备使用命令列表之前,我们需要先将其重置,并重新绑定分配器

  • CPU向GPU递交命令时,为了加快速度,是一次性提交一批命令的,而这些命令就记录在命令列表中
  • 分配器顾名思义,用于记录命令



命令列表重置与分配

绘制调用前,我们需要设置绘制目标、绘制视口、裁剪矩形等,并将绘制目标、深度图清空为默认颜色

  • 这里还有等待GPU使用完毕当前资源的步骤,简单查看代码即可,不再赘述



设置视口,裁剪矩形,重置绘制资源、深度图等

之后,我们可以绑定所有根常量

  • 在本章中,我们仅绑定了一个变换矩阵,在下一章说明
在上面的准备工作都完成后,我们即可进行绘制调用

  • 当我们指定了索引缓冲区时,绘制调用需要为DrawIndexedInstanced



绘制调用

在绘制调用完毕后,我们需要关闭命令列表,然后将命令列表提交到命令队列中

  • 命令队列负责实际的从CPU到GPU的命令递交
  • 这里还有前台后台缓冲区的交换,不再赘述



递交命令,并等待命令执行完成
回复

使用道具 举报

2

主题

3

帖子

8

积分

新手上路

Rank: 1

积分
8
发表于 2025-4-12 15:54:06 | 显示全部楼层
看起来不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|开发者网络

GMT+8, 2025-4-20 02:12 , Processed in 0.155366 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表