【发布时间】:2016-02-04 07:46:07
【问题描述】:
我注意到我的 nvidia 860m 上有一些超级奇怪的行为。我正在编写一些 3d 引擎,我正在使用曲面细分进行地形渲染。
我使用简单的四边形细分算法。
struct PatchTess
{
float EdgeTess[4] : SV_TessFactor;
float InsideTess[2] : SV_InsideTessFactor;
};
PatchTess ConstantHS(InputPatch<VS_OUT, 4> patch)
{
PatchTess pt;
float3 l = (patch[0].PosW + patch[2].PosW) * 0.5f;
float3 t = (patch[0].PosW + patch[1].PosW) * 0.5f;
float3 r = (patch[1].PosW + patch[3].PosW) * 0.5f;
float3 b = (patch[2].PosW + patch[3].PosW) * 0.5f;
float3 c = (patch[0].PosW + patch[1].PosW + patch[2].PosW + patch[3].PosW) * 0.25f;
pt.EdgeTess[0] = GetTessFactor(l);
pt.EdgeTess[1] = GetTessFactor(t);
pt.EdgeTess[2] = GetTessFactor(r);
pt.EdgeTess[3] = GetTessFactor(b);
pt.InsideTess[0] = GetTessFactor(c);
pt.InsideTess[1] = pt.InsideTess[0];
return pt;
}
[domain("quad")]
[partitioning("fractional_even")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
[maxtessfactor(64.0f)]
VS_OUT HS(InputPatch<VS_OUT, 4> p, uint i : SV_OutputControlPointID)
{
VS_OUT vout;
vout.PosW = p[i].PosW;
return vout;
}
[domain("quad")]
DS_OUT DS(PatchTess patchTess, float2 uv : SV_DomainLocation, const OutputPatch<VS_OUT, 4> quad)
{
DS_OUT dout;
float3 p = lerp(lerp(quad[0].PosW, quad[1].PosW, uv.x), lerp(quad[2].PosW, quad[3].PosW, uv.x), uv.y);
p.y = GetHeight(p);
dout.PosH = mul(float4(p, 1.0f), gViewProj);
dout.PosW = p;
return dout;
}
上面这段代码不是问题,只是想给你一些代码上下文。
此函数出现问题:
inline float GetTessFactor(float3 posW)
{
const float factor = saturate((length(gEyePos - posW) - minDistance) / (maxDistance - minDistance));
return pow(2, lerp(6.0f, 0.0f, factor));
}
当我在 Visual Studio 中使用调试模式时,一切正常,镶嵌可以正常工作。但是在发布模式下,我得到了地形补丁的闪烁。
现在超级奇怪的事情:当我改变函数并从 pow 切换到线性函数或其他东西时,一切都按预期工作。 所以这很好用:
inline float GetTessFactor(float3 posW)
{
const float factor = saturate((length(gEyePos - posW) - minDistance) / (maxDistance - minDistance));
return lerp(64.0f, 0.0f, factor));
}
编辑: 换行:
pt.InsideTess[0] = GetTessFactor(c);
到
pt.InsideTess[0] = max(max(pt.EdgeTess[0], pt.EdgeTess[1]), max(pt.EdgeTess[2], pt.EdgeTess[3]));
完成这项工作。
似乎有时 pow 函数正在计算对边缘测试因子无效的值(有效范围为 64.0f)。
另外请记住,这个问题只会出现在发布模式下运行而不是调试模式下(VS 2013)。
有人知道 tessfactor 值组合的限制吗?我没有在 msdn 或任何类似页面上找到任何信息。
谢谢
【问题讨论】:
-
我唯一能想到的是
pow变体以某种方式产生了NaN值,这可能是由于2文字的优化。如果它没有出现在调试器中,您可以尝试添加一个isnan对返回值的检查并写入一个您可以读回并在 CPU 上打印的 UAV。或者直接将返回值写入无人机。 -
感谢您的回答。我已经尝试过了,并且 pow 功能似乎没问题。经过进一步的试验和错误,我发现问题出在 tessFactors 上。不知何故,值组合必须有一些限制。我已将 insideTessFactor 的行更改为 pt.InsideTess[0] = max(max(pt.EdgeTess[0], pt.EdgeTess[1]), max(pt.EdgeTess[2], pt.EdgeTess[3 ]));它可以正常工作。在 msdn 或类似页面上没有找到任何 cmets。
-
因新信息而更改了描述
-
SV_TessFactor和SV_InsideTessFactor之间的关系不应该有任何限制。如果其中一个是0,尽管补丁将被剔除。尽管这只发生在 DEBUG 版本中,但这是值得怀疑的。这表明某处的竞争条件仅出现在 RELEASE 构建中(当事情运行得更快时)。我要尝试的下一件事是为 RELEASE 构建,但尝试使用 VS Graphics Debugger 捕获帧。我建议使用 VS 2015,因为工具自 2013 年以来已经改进。
标签: directx-11 hlsl tessellation