十五、D3D12学习笔记——曲面细分

十五、D3D12学习笔记——曲面细分曲面细分 可以说是流水线上对前后依赖关系最不明显 相对独立的部分了 配置都是流水线式的 制定规则 硬件执行 细部调整

大家好,欢迎来到IT知识分享网。

曲面细分:将几何体细分为更小的三角形并偏移产生曲面,达到细节丰富的效果。工作都在shader中,进行格式的配置即可。

一、CPU侧

启用了曲面细分,就要把点作为控制点来传输:

1.图元装配阶段

cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST);

2.PSO定义阶段

opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; opaquePsoDesc.HS =     {         reinterpret_cast<BYTE*>(mShaders["tessHS"]->GetBufferPointer()),         mShaders["tessHS"]->GetBufferSize()     };     opaquePsoDesc.DS =     {         reinterpret_cast<BYTE*>(mShaders["tessDS"]->GetBufferPointer()),         mShaders["tessDS"]->GetBufferSize()     };

以上就是在CPU端从设置PSO和绑定渲染流水线的控制点图元设置全过程。其中输入装配可以根据控制点个数具有不同的类型(修改格式而已,从1-32)

十五、D3D12学习笔记——曲面细分

二、GPU侧

应用曲面细分之后,顶点着色器处理对象就是单个控制点,可用于对控制点进行调整:

1.顶点着色器

VertexOut VS(VertexIn vin) {     VertexOut vout;          vout.PosL = vin.PosL;//不调整数据,只做传递用     return vout; }

出了顶点着色器,就进入外壳着色器

2.外壳着色器

所谓外壳着色器就是一种规则的制定者,共分为两种:常量外壳着色器控制点外壳着色器

1).常量外壳着色器HS

如上,指定4个控制点,实际意义就是将4个控制点组成一个单个面片。常量HS的作用就是处理单个面片(处理一个面片就调用一次),输出该面片细分的因子(边缘与内部细分方式):

struct PatchTess {     float EdgeTess[4]   : SV_TessFactor;//四条边细分因子,几边形就是几条边     float InsideTess[2] : SV_InsideTessFactor;//内部细分因子,三角形一个,四边形两个(横竖) }; 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;     pt.InsideTess[1] = 3;         return pt; }

注意:

  1. InputPatch<VertexOut, 4> patch表示是由顶点着色器输出的4个控制点构成的一个面片;
  2. 每个面片具有独立的图元索引:uint patchID : SV_PrimitiveID;
  3. 返回值    return pt;将细分因子返回至流水线以供调用。

2).控制点外壳着色器HS

以大量的控制点作为输入与输出,每输出一个控制点着色器被调用一次。

龙书对这个部分有大量的叙述,什么PN三角形法,N-patches方法啥的。个人感觉没太大感触,这个控制点外壳着色器,就是细分规则的制定者。

struct HullOut {     float3 PosL : POSITION; }; [domain("quad")]//面片类型(quad / tri / isoline) [partitioning("integer")]//剔除小数部分,使用细分因子整数部分,如果考虑小数(fractional_even / fractional_odd) [outputtopology("triangle_cw")]//细分生成的三角形绕序(自动组织定义正反面),对线段细分则:line [outputcontrolpoints(4)]//控制点个数,一个控制点HS执行一次 [patchconstantfunc("ConstantHS")]//指定常量外壳着色器以获得细分因子 [maxtessfactor(64.0f)]//钳制最大细分因子 HullOut HS(InputPatch<VertexOut, 4> p, //同常量HS,从顶点着色器过来            uint i : SV_OutputControlPointID,//控制点ID,单次执行用于索引点            uint patchId : SV_PrimitiveID) {     HullOut hout; //更复杂的逻辑,可以调整输出控制点点位置         hout.PosL = p[i].PosL;         return hout; }

3.镶嵌化

通过两个HS,我们似乎只是制定了曲面划分的规则,但是控制点还是那些控制点,没有任何变化。那我们的规则到底谁来执行呢?答案就是镶嵌化。

镶嵌化会根据我们指定的规则:

1.ConstantHS部分细分因子以SV_TessFactor,SV_InsideTessFactor标记的内容被系统识别;

2.HS部分通过[]指定了一堆规则

通过硬件在两个控制点之间进行插值,并给出在控制点构成的面片空间下的uv(w)坐标,表示插值生成的新点位置。提供给域着色器使用。

4.域着色器

struct DomainOut {     float4 PosH : SV_POSITION;//此时才产生真正用于场景顶点的坐标,代替原顶点着色器部分 }; [domain("quad")]//面片类型,4个控制点的,注意全过程的对应 DomainOut DS(PatchTess patchTess, //虽然这里有曲面细分但是似乎没使用过              float2 uv : SV_DomainLocation, //由镶嵌化对控制点间使用细分因子插值得到的uv(w)              const OutputPatch<HullOut, 4> quad)//从HS穿过来的控制点 {     DomainOut dout;     // 使用uv双线性插值.对于三角形就是uvw的中心坐标插值     float3 v1 = lerp(quad[0].PosL, quad[1].PosL, uv.x);      float3 v2 = lerp(quad[2].PosL, quad[3].PosL, uv.x);      float3 p  = lerp(v1, v2, uv.y);      // 偏移使之成为曲面,丰富细节     p.y = 0.3f*( p.z*sin(p.x) + p.x*cos(p.z) );    float4 posW = mul(float4(p, 1.0f), gWorld);  dout.PosH = mul(posW, gViewProj);       return dout; }

之后交给PS,就好像VS交给PS数据一样处理。

三、基于视点距离的曲面细分例子

这里只分享shader部分代码,因为CPU段顶点配置是非常easy的任务。

struct VertexIn {     float3 PosL    : POSITION; }; struct VertexOut {     float3 PosL    : POSITION; }; VertexOut VS(VertexIn vin) {     VertexOut vout;          vout.PosL = vin.PosL;     return vout; }   struct PatchTess {     float EdgeTess[4]   : SV_TessFactor;     float InsideTess[2] : SV_InsideTessFactor; }; PatchTess ConstantHS(InputPatch<VertexOut, 4> patch, uint patchID : SV_PrimitiveID) {     PatchTess pt;          float3 centerL = 0.25f*(patch[0].PosL + patch[1].PosL + patch[2].PosL + patch[3].PosL);     float3 centerW = mul(float4(centerL, 1.0f), gWorld).xyz;          float d = distance(centerW, gEyePosW);     // Tessellate the patch based on distance from the eye such that     // the tessellation is 0 if d >= d1 and 64 if d <= d0.  The interval     // [d0, d1] defines the range we tessellate in.          const float d0 = 20.0f;     const float d1 = 100.0f; //注意等于1表示不细分,0表示剔除     float tess = max(64.0f*saturate( (d1-d)/(d1-d0) ),1.0);     // Uniformly tessellate the patch.     pt.EdgeTess[0] = tess;     pt.EdgeTess[1] = tess;     pt.EdgeTess[2] = tess;     pt.EdgeTess[3] = tess;          pt.InsideTess[0] = tess;     pt.InsideTess[1] = tess;          return pt; } 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;          return hout; } struct DomainOut {     float4 PosH : SV_POSITION; }; // The domain shader is called for every vertex created by the tessellator.   // It is like the vertex shader after tessellation. [domain("quad")] DomainOut DS(PatchTess patchTess,               float2 uv : SV_DomainLocation,               const OutputPatch<HullOut, 4> quad) {     DomainOut dout;          // Bilinear interpolation.     float3 v1 = lerp(quad[0].PosL, quad[1].PosL, uv.x);      float3 v2 = lerp(quad[2].PosL, quad[3].PosL, uv.x);      float3 p  = lerp(v1, v2, uv.y);           // Displacement mapping     p.y = 0.3f*( p.z*sin(p.x) + p.x*cos(p.z) );          float4 posW = mul(float4(p, 1.0f), gWorld);     dout.PosH = mul(posW, gViewProj);          return dout; } float4 PS(DomainOut pin) : SV_Target {     return float4(1.0f, 1.0f, 1.0f, 1.0f); }

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/124409.html

(0)
上一篇 2025-10-07 19:20
下一篇 2025-10-07 19:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信