基于HLSL的高度图地形曲面细分无画面输出问题排查求助
先从你的代码里几个关键问题入手,这些大概率是导致无输出的核心原因:
1. Hull Shader常量函数中的致命越界访问
看你的ConstantHS函数里这段代码:
float3 distance = inputPatch[patchId].position.xyz - cameraPosition.xyz;
inputPatch是当前补丁的3个控制点数组,合法索引只有0,1,2,但patchId是当前补丁的全局ID(比如第0个补丁、第1个补丁...),用它来索引inputPatch必然会越界!这会触发非法内存访问,直接导致渲染管线崩溃,自然看不到任何输出。
修复方法:如果你想基于补丁到相机的距离计算 tess 因子,应该取补丁的中心点或者任意一个固定控制点来计算,比如:
// 取补丁第一个控制点计算到相机的距离 float3 distanceVec = inputPatch[0].position3D - cameraPosition; float distLength = length(distanceVec);
另外你现在直接把tess因子硬编码成4.0,可以先保留这个硬编码,先让渲染正常跑起来,再优化动态tess逻辑。
2. Domain Shader中的法线计算完全错误
你的Domain Shader里这段法线处理逻辑完全不符合要求:
output.normal = mul(float4(vertexPosition, 1.0f), worldMatrix); output.normal = normalize(output.normal);
这是把顶点位置乘以世界矩阵后当作法线使用!正确的做法是:
- 首先,你应该基于高度图修改后的顶点位置推导法线(或者先暂时用默认法线测试)
- 其次,法线需要用世界矩阵的逆转置来变换,而不是直接用世界矩阵
临时修复:先设置一个默认向上的法线,确保地形能显示:
// 把世界空间的向上向量作为法线 output.normal = normalize(mul(float3(0,1,0), (float3x3)worldMatrix));
3. Domain Shader中高度图采样逻辑混乱且低效
你用循环修改顶点Y的逻辑既不合理又严重影响性能:
for (float i = 1.0f; i >= 0.0f; i -= 0.01f) { if (textureColor.r > i) { vertexPosition.y -= i * 0.5f; normalPosition.y -= abs(0.9 * 15.0f); } }
高度图的正确用法是直接用采样值缩放高度,比如:
// 用height常量控制高度缩放幅度 vertexPosition.y += textureColor.r * height;
4. 常量缓冲区寄存器存在冲突风险
你的Hull Shader里CameraBuffer用了register(cb0),而Domain Shader里MatrixBuffer也用了register(cb0)。虽然D3D11中每个着色器阶段的常量缓冲区寄存器是独立的,但如果应用层绑定缓冲区时搞错了(比如把MatrixBuffer绑定到Hull Shader的cb0),会导致Hull Shader读取错误数据,引发异常。
建议:为不同着色器阶段的常量缓冲区分配不同寄存器,比如Hull Shader的CameraBuffer用cb1,Domain Shader的MatrixBuffer保留cb0,避免混淆。
5. 快速排查验证步骤
- 先把Pixel Shader改成直接返回红色:
return float4(1.0, 0.0, 0.0, 1.0);,如果还是没输出,说明问题出在VS/HS/DS阶段或者管线设置环节。 - 检查顶点数据是否正确:每个补丁的3个顶点是否构成有效三角形,
position3D是否正确填充了模型空间位置。 - 确认应用层管线设置:是否正确绑定了HS/DS着色器,是否设置了
D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST拓扑,常量缓冲区是否正确绑定到对应着色器阶段。
内容的提问来源于stack exchange,提问作者Carrot Cake

