使用 DirectX 11 的 HLSL pow() 函数的奇怪行为

Strange behaviour of HLSL pow() function using DirectX 11

我正在根据 Frank Luna 等许多示例编写 DX11 SM5.0 地形船体着色器。在调查(线框)地形疯狂闪烁的原因时,我发现 pow() 函数似乎存在问题。

我计算镶嵌因子的代码是:

float CalcTessFactor(float3 p)
{
    float d = distance(p, cameraPosition);
    float s = saturate((d - 1000.0f) / (5000.0f - 1000.0f));
    //return pow(2, (lerp(6, 1, s)));
    return saturate((5000.0f - d) / 5000.0f)*64.0f;
}

硬编码数字常量是我减少调试的一部分。注释掉的行:“//return pow(...”是原始代码,我已将其替换为现在后面的行。

有了这个替换,曲面细分就完全稳定了,并且随着与相机的距离的增加而减少。正如预期的那样,减少只是线性的而不是对数的,但至少它有效,被很好地镶嵌并且没有闪烁的迹象。

使用原始代码,网格似乎以帧速率在明显随机的曲面细分因子之间切换。

任何人都可以提出可能出了什么问题吗?

我的补丁常量函数是:

struct HullInputType
{
    float3 position : POSITION;
    float4 color : COLOR;
};

struct ConstantOutputType
{
    float edges[4] : SV_TessFactor;
    float inside[2] : SV_InsideTessFactor;
};

ConstantOutputType TerrainPatchConstantFunction(InputPatch<HullInputType, 4> patch, uint patchId : SV_PrimitiveID)
{
    ConstantOutputType output;

    // Compute midpoint on edges, and patch center
    // order of vertices is: 0 1
    //                       2 3
    float3 e0 = 0.5f*(patch[0].position + patch[2].position);
    float3 e1 = 0.5f*(patch[0].position + patch[1].position);
    float3 e2 = 0.5f*(patch[1].position + patch[3].position);
    float3 e3 = 0.5f*(patch[2].position + patch[3].position);
    float3 c = 0.25f*(patch[0].position + patch[1].position + patch[2].position + patch[3].position);

    // Set the tessellation factors for the four edges of the quad.
    output.edges[0] = CalcTessFactor(e0);
    output.edges[1] = CalcTessFactor(e1);
    output.edges[2] = CalcTessFactor(e2);
    output.edges[3] = CalcTessFactor(e3);

    // Set the tessellation factor for tessallating inside the quad.
    output.inside[0] = CalcTessFactor(c);
    output.inside[1] = output.inside[0];

    return output;
}

查看您的 return 值。看起来您正在向后进行镶嵌。取消注释代码的价格。硬编码距离值说 1000。你应该得到一致的镶嵌。如果你这样做,那么你应该不会闪烁。如果你不这样做,那么它与你断言或不断言的幂函数有关,那么你的距离向量很时髦。

编辑:添加了我的曲面细分功能以供参考。

  struct VertexOut
{
    float4 PosW : POSITION0;
    float4 waterAttributes : POSITION2;
    float4 direction : POSITION1;
//    float4 wind : POSITION2;
    float tessFactor : TESS;
};

//========================================================================================================================

[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("PatchHS")]
HullOut HSMain(InputPatch<VertexOut, 3> p,
           uint i : SV_OutputControlPointID,
           uint patchId : SV_PrimitiveID)
{
    HullOut hout;

    // Pass through shader.
    hout.PosW = p[i].PosW;
    hout.direction = p[i].direction;
    hout.waterAttributes = p[i].waterAttributes;
 //   hout.wind = p[i].wind;

    return hout;
}

PatchTess PatchHS(InputPatch<VertexOut, 3> patch,
                  uint patchID : SV_PrimitiveID)
{
    PatchTess pt;

    // Average tess factors along edges, and pick an edge tess factor for 
    // the interior tessellation.  It is important to do the tess factor
    // calculation based on the edge properties so that edges shared by 
    // more than one triangle will have the same tessellation factor.  
    // Otherwise, gaps can appear.
    pt.EdgeTess[0] = 0.5f * (patch[1].tessFactor + patch[2].tessFactor);
    pt.EdgeTess[1] = 0.5f * (patch[2].tessFactor + patch[0].tessFactor);
    pt.EdgeTess[2] = 0.5f * (patch[0].tessFactor + patch[1].tessFactor);
    pt.InsideTess = pt.EdgeTess[0];

    return pt;
}