您现在的位置是:首页 >学无止境 >Direct3D 12——曲面细分阶段——外壳着色器网站首页学无止境
Direct3D 12——曲面细分阶段——外壳着色器
外壳着色器是由两种着色器(phase )组成的:1.常量外壳着色器;2.控制点外壳着色器。
常量外壳着色器
常量外壳着色器(constant hull shader )会针对每个面片逐一进行处理(即每处理一个面片就被调用一次),它的任务是输出网格的曲面细分因子(tessellationfactor,也有译作细分因子、镶嵌因子等)。曲面细分因子指示了在曲面细分阶段中将面片镶嵌处理后的份数。下面是一个具有4个控制点的四边形面片(quad patch)示 例,我们将它从各个方面均匀地镶嵌细分为3份。
struct PatchTess
{
float EdgeTess[4] : SV_TessFactor;
float InsideTess[2] : SV_InsideTessFactor;
//可以在下面为每个面片附加所需的额外信息
};
PatchTess ConstantHS(InputPatch<VertexOut, 4> patch, uint patchlD : 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.两个内部曲面细分因子指示了如何来对该四边形面片的内部进行镶嵌化处理(一个曲面细分因 子针对四边形的横向维度,另一个则作用于四边形的纵向维度)。
对三角形面片(trianglepatch)执行镶嵌化处理的过程同样分为两部分:
1.3个边缘曲面细分因子控制着对应边上镶嵌后的份数。
2.一个内部曲面细分因子指示着三角形面片内部的镶嵌份数。
Direct3D 11硬件所支持的最大曲面细分因子为64。如果把所有的曲面细分因子都设置为0,则该面片会被后续的处理阶段丢弃。这就使我们能够以每个面片为基准来实现如视锥体剔除(frustum culling ) 与背面剔除这类优化。
1.如果面片根本没有出现在视锥体范围内,那么就能将它从后续的处理中丢弃(倘若已经对该面片进行了镶嵌化处理,那么其细分后的各三角形将在三角形裁剪(triangleclipping)期间被抛弃)。
2.如果面片是背面朝向的,那么就能将其从后面的处理过程中丢弃(如果该面片已经过了镶嵌化 处理,则其细分后的诸三角形会在光栅化阶段的背面剔除过程中被遗弃)。
一个问题自然而然地浮现出来:到底应该执行几次镶嵌化处理才合适?前面提到,曲面细分的基本想法就是为了丰富网格的细节。但是,如果用户对此无感,我们就不必无谓地为它增添细节了。以下是一些确定镶嵌次数的常用衡量标准。
1.根据与摄像机之间的距离:物体与摄像机的距离越远,能分辨的细节就越少。因此,我们在两 者距离较远时渲染物体的低模版本,并随着两者逐渐接近而逐步对物体进行更加细致的镶嵌化细分。
2.根据占用屏幕的范围:可以先估算出物体覆盖屏幕的像素个数。如果数量比较少,则渲染物体 的低模版本。随着物体占用屏幕范围的增加,我们便可以逐渐增大镶嵌化细分因子。
3.根据三角形的朝向:三角形相对于观察者的朝向也被列入考虑的范畴之中。位于物体轮廓边缘 (silhouette edge )上的三角形势必比其他位置的三角形拥有更多的细节。
4.根据粗糙程度:粗糙不平的表面较光滑的表面需要进行更为细致的曲面细分处理。通过对表面 纹理进行检测可以预算出相应的粗糙度数据,继而来决定镶嵌化处理的次数。
以下几点关于性能的建议:
1.如果曲面细分因子为1 (这个数值其实意味着该面片不必细分),那么就考虑在渲染此面片时不 对它进行细分处理;否则,便会在曲面细分阶段白白浪费GPU资源,因为在此阶段并不对其执行任何操作。
2.考虑到性能又涉及GPU对曲面细分的具体实现,所以不要对小于8个像素这种过小的三角形进 行镶嵌化处理。
3.使用曲面细分技术时要采用批绘制调用(batch draw call,即尽量将曲线细分任务集中执行)(在 绘制调用之间往复开启、关闭曲面细分功能的代价极其高昂)
控制点外壳着色器
控制点外壳着色器(control point hull shader)以大量的控制点作为输入与输出,每输出一个控制点,此着色器都会被调用一次。该外壳着色器的应用之一是改变曲面的表示方式,比如说把一个普通的三角形(向渲染流水提交的3个控制点)转换为3次贝塞尔三角形面片(cubic Bezier triangle patch,即一种具有10个 控制点的面片)。例如,假设我们像平常那样利用(具有3个控制点的)三角形对网格进行建模,就可以通过控制点外壳着色器,将这些三角形转换为具有10个控制点的高阶三次贝塞尔三角形面片。新增的控制点不仅会带来更丰富的细节,而且能将三角形面片镶嵌细分为用户所期望的份数。这一策略被称为N-patches方法 (法线一面片方法,normal-patches scheme)或PN三角形方法(即(曲面)点一法线三角形方法,(curved ) point-normal triangles,简记作PN triangles scheme )。由于这种方案只需用曲面细分技术来改进已存在的三角形网格,且无须改动美术制作流程,所以实现起来比较方便。控制点外壳着色器仅充当一个简单的传递着色器(pass-through shader ),它不会对控制点进行任何的修改。
struct HullOut
{
float3 PosL : POSITION;
};
[domain("quad")]
[partitioning ("integer**)]
[outputtopology(ntriangle_cwH)]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
[maxtessfactor(64.Of)]
HullOut HS(InputPatch<VertexOut, 4> p,uint i : SV_OutputControlPointID, uint patchld : SV_PrimitiveID)
{
HullOut hout;
hout.PosL = p[i].PosL;
return hout;
}
通过InputPatch参数即可将面片的所有控制点都传至外壳着色器之中。系统值SV_ OutputControlPointID索引的是正在被外壳着色器所处理的输出控制点。值得注意的是,输入的控制点数量与输出的控制点数量未必相同。例如,输入的面片可能仅含有4个控制点,而输出的面片却能 够拥有16个控制点;意即,这些多出来的控制点可由输入的4个控制点所衍生。
上面的控制点外壳着色器还用到了以下几种属性。
1.domain:面片的类型。可选用的参数有tri (三角形面片)、quad (四边形面片)或isoline (等值线)。
2.partitioning:指定了曲面细分的细分模式。
a.integer。新顶点的添加或移除仅取决于曲面细分因子的整数部分,而忽略它的小数部分。这样一来,在网格随着曲面细分级别而改变时,会容易发生明显的突跃(popping ) 的情况。
b.非整型曲面细分(fractional_even/fractional_odd)。新顶点的添加或移除取决于曲面细分因子的整数部分,但是细微的渐变“过渡”调整就要根据因子的小数部分。当我们希望将粗糙的网格经曲面细分而平滑地过渡到具有更佳细节的网格时,该参数就派上用 场了。理解整型细分与非整型细分之间差别的最佳方式就是通过动画实际演示、比对,因 此,本章末会有相应的练习来令读者比较两者的差异。
3.outputtopology:通过细分所创的三角形的绕序。
a.triangle_cw:顺时针方向的绕序。
b.triangle_ccw:逆时针方向的绕序。
c.line:针对线段曲面细分。
4.outputcontrolpoints :外壳着色器执行的次数,每次执行都输出1个控制点。系统值 SV_OutputControlPointID给出的索引标明了当前正在工作的外壳着色器所输出的控制点。
5.patchconstantfunc:指定常量外壳着色器函数名称的字符串。
6.maxtessfactor:告知驱动程序,用户在着色器中所用的曲面细分因子的最大值。如果硬件 知道了此上限,便可了解曲面细分所需的资源,继而就能在后台对此进行优化。Direct3D 11硬 件支持的曲面细分因子最大值为64。