词汇
控制点:control point 面片:patch 外壳着色器:hull shader 相:phase 控制点外壳着色器:control point hull shader
常量外壳着色器:constant hull shader 曲面细分因子:tessellation factor 四边形曲面:quad patch
三角形面片:triangle patch 视椎体剔除:frustum culling 轮廓边缘:silhouette edge
批绘制调用:batch draw call 3次贝塞尔三角形面片:cubic Bezier triangle patch
N-Patches方法:normal-patches scheme PN三角形方法:point-normal triangles scheme
传递着色器:pass-through shader
内容
14.1曲面细分的图元类型
在进行曲面细分时,并不向输入装配器提交三角形,而是提交具有若干控制点的面片DirectX支持具有1~32个控制点的面片,用以下图源类型来描述。
D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
.
.
.
D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64,
由于可以将三角形看做3个控制点的三角形面片,所以我们依然可以提交需要镶嵌画处理的普通三角形网格,对于简单的四边形面片,提交4个控制点的面片即可,这些面片最终会在曲面细分阶段经镶嵌化处理分解成多个三角形。
*在向ID3D12GraphicsCommandList::IASetPrimitiveTopology方法传递控制点图元类型时,还需要把D3D12_GRAPHICS_PIPELINE_DESC::PrimitiveTopoLogyType字段设置为D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,如opaquePsoDesc.PrimitiveTopologyType=D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH。
控制点的概念来源于特定种类数学角度上特定曲线或曲面的构造过程,如贝塞尔曲线。例如我们可以通过9个控制点或16个控制点创建一个贝塞尔四边形面片,控制点越多,我们对面片的形状控制就更加随心所欲。因此这一切图元控制类型都是为了给这些不同种类的曲线、曲面的绘制提供支持,
曲面细分与顶点着色器
在向渲染流水线提交了面片的控制点之后,他们就会被推送至顶点着色器,此时顶点着色器就成为了“处理控制点的着色器”,我们还可以在曲面细分开始之前对控制点进行一些调整,一般动画与物理模拟的计算工作都会在对几何体进行镶嵌化处理之前的顶点着色器中以较低的频次进行(镶嵌化处理后顶点数量增多,处理的频次也会相对增加)。
14.2 外壳着色器
外壳着色器实际由两种着色器组成:
- 常量外壳着色器
- 控制点外壳着色器
14.2.1常量外壳着色器
常量外壳着色器会对每个面片逐一进行处理(每处理一个面片都会被调用一次),它的认任务是输出网格的曲面细分因子,曲面细分因子指示了在曲面细分阶段将面片镶嵌处理后的份数,下面是一个具有4个控制点的四边形面片示例,我们将它从各个方面均匀的镶嵌细分为3份
struct PatchTess
{
float EdgeTess[4] : SV_TessFactor;
float InsideTess[2] : SV_Inside_TessFactor;
//可以在下面为每个面片附加所需的额外信息
}
PatchTess ConstantHS(InputPatch<VertexOut, 4> patch, uint patchID : SV_PrimitiveID)
{
PatchTess pt;
//将该面片从各方面均匀的镶嵌处理为3等分
pt.EdgeTess[0] = 3;
pt.EdgeTess[1] = 3;
pt.EdgeTess[2] = 3;
pt.EdgeTess[3] = 3;
pt.InsideTess[0] = 3;//u轴,四边形内部细分的列数
pt.InsideTess[1] = 3;//v轴,四边形内部细分的行数
return pt;
}
常量外壳着色器以面片的所有控制点作为输入,在此用InputPatch<VertexOut,4>对此进行定义。控制首先会传至顶点着色器,因此它们的类型有顶点着色器的输出类型VertexOut来确定, 此例中的面片拥有4个控制点,所以将InputPatch模板的第二个参数指定为4,系统还通过SV_PrimitiveID语义提供了面片的ID值,此ID唯一标识了绘制调用过程中的各个面片,可以根据具体的需求进行运用。常量外壳着色器必须输出曲面细分因子,该因子取决于面片的拓扑结构。
SV_TessFactor与SV_InsideTessFactor 分别表示几何图形边缘与内部的细分份数,除此之外还可以令外壳着色器输出其它的面片信息,域主色器接受来自外壳着色器的输出数据作为输入,继而使用这些额外的面片信息。
对四边形面片进行镶嵌化处理的过程分为两个部分:
1. 4个边缘曲面细分因子控制着对应边缘镶嵌后的份数
2. 两个内部曲面细分因子指示了如何对该四边形面片的内部进行镶嵌化处理(一个曲面细分因子针对四边形的横向维度,另一个则作用于四边形的纵向维度)
该图展示了不同曲面细分因子会生成结构各异的四边形面片。
对三角形面片执行镶嵌化处理的过程分为两部分:
- 三个边缘曲面细分因子控制着对应边上镶嵌后的份数
- 一个内部曲面细分因子指示三角形面片内部的镶嵌份数
图中所示即通过不同曲面细分因子最终得到的结构各异的三角形面片。
Direct3D12中所支持的最大曲面细分因子为64,如果把所有曲面细分因子都设置为0,则 该面片会被后续处理阶段丢去,就能使我们能够以每个面片为基准实现如视椎体剔除与背面剔除这类优化。
1. 如果面片没有出现在视椎体内,就能将它从后续处理中丢弃
2. 如果面片是背面朝向的,就能将其从后续处理中丢弃
镶嵌处理次数的常用衡量标注:
1. 根据与摄像机之间的距离:物体离摄像机越远,能分辨的细节也就越少,因此我们在两者较远时渲染低模, 并随着两者逐渐接近而逐步对物体进行更细致的镶嵌化处理。
2. 占用屏幕的范围:可以先估算出物体覆盖屏幕的像素个数,如果数量较少,则渲染低模版本,随着占用屏幕范围的增加,便可以逐渐增大镶嵌化细分因子。
3. 根据三角形朝向:位于物体轮廓边缘上的三角形势必比其它位置的三角形具有更多细节。
4. 根据粗糙程度:粗糙表面比光滑表面更需要细致的曲面细分处理。通过对表面的纹理进行检测可以预算处相应的粗糙度数据,继而决定镶嵌化处理的次数
几点关于性能的建议:
1. 如果曲面细分因子为1,则考虑在渲染此片面时不进行细分处理,否则会白白浪费GPU资源
2. 不要对小于8个像素的三角形进行镶嵌化处理
3. 使用曲面细分技术时要采用批绘制调用(尽量将曲面细分任务集中执行,在绘制调用之间反复开启关闭曲面细分功能的代价机器高昂)。
14.2.2控制点外壳着色器
控制点外壳着色器以大量的控制点作为输入与输出,每输出一个控制点,此着色器就会被调用一次。应用之一是改变曲面的表示方式,比如把一个普通三角形转换为3次贝塞尔三角形面片。例如像通常一样对三角形进行建模,就可以通过控制点外壳着色器将这些三角形转换玩具有10个控制点的高阶三次贝塞尔三角形面片,新增的控制点不仅会带来更丰富的细节,还能将三角形面片镶嵌细分为用户希望的分数。这一策略分为N-patches方法或PN三角形方法。这种方案只需要曲面细分技术来改进已存在的三角形网格,且无需改动美术的制作流程,所以实现起来比较方便。对于本章第一个例程,控制点外壳着色器仅充当一个简单的传递着色器,不会对控制点进行任和修改。
struct HullOut
{
float3 PosL : POSITION;
}
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
[maxtessfactor(64.0f)]
HullOut HS(InputPatch<VertexOut,4> p,
uint i : SV_OutputControlPointID,
uint patchID : SV_PrimitiveID)
{
HullOut hout;
hout.PosL = p[i].PosL;
renturn hout;
}
通过InputPatch参数即可将面片的所有控制点船只外壳着色器中。系统值SV_OutputControlPointID索引的是正在被外壳着色器所处理的输出控制点,输入的控制点数量与输出的控制点数量未必相同,输入的面片可能只有4个控制点,输出的面片却能拥有16个控制点。
上面的控制点外壳着色器还用到了以下几种属性:
- domain:面片类型,可选用的参数又tri,quad或isoline
- partitioning:指定曲面细分的模式
integer:新顶点的添加或一食醋取决于曲面细分因子的整数部分,忽略它的小数部分,这样一来在网格随着曲面细分级别而改变时,会容易发生明显的突跃
非整形曲面细分(fractional_even/fracional_odd)。新顶点的添加或移除取决于曲面细分因子的整数部分,但是细微的渐变“过渡”调整就要根据因子的小数部分。当我们希望将词槽的网格经曲面细分而平滑的过渡到具有更加细节的网格时,该参数就派上用场。 - outputtopology:通过 细分所创的三角形绕序
a. triangle_cw:顺时针绕序
b. triangle_ccw:逆时针绕序
c. line:针对线段的曲面细分 - outputcontrolpoints:外壳着色器执行次数,每次执行都输出1个控制点,系统值SV_OutputControlPointID给出的索引标明了当前正在工作的外壳着色器所输出的控制点。
- patchcontantfunc:指定常量外壳着色器函数名称的字符串
- maxtessfactor:告知驱动程序,用户在着色器中所使用的曲面细分因子的最大值,如果硬件知道了这个上限,便可以了解曲面细分所需的资源,继而就能在后台对此进行优化,Direct3D 11硬件支持的曲面细分因子最大为64。