【问题标题】:Strange behavior of tessFactors inside tessellation stage镶嵌阶段内 tessFactors 的奇怪行为
【发布时间】: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_TessFactorSV_InsideTessFactor 之间的关系不应该有任何限制。如果其中一个是0,尽管补丁将被剔除。尽管这只发生在 DEBUG 版本中,但这是值得怀疑的。这表明某处的竞争条件仅出现在 RELEASE 构建中(当事情运行得更快时)。我要尝试的下一件事是为 RELEASE 构建,但尝试使用 VS Graphics Debugger 捕获帧。我建议使用 VS 2015,因为工具自 2013 年以来已经改进。

标签: directx-11 hlsl tessellation


【解决方案1】:

最新的驱动程序更新解决了问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 2016-03-10
    相关资源
    最近更新 更多