Barbarian
Barbarian

Reputation: 247

Strange behaviour of HLSL pow() function using DirectX 11

I'm programming a DX11 SM5.0 terrain hull shader along the lines of many examples such as Frank Luna's. While investigating the reason for crazy flickering of the (wireframe) terrain, I've homed in on what seems to be a problem with the pow() function.

My code to calculate tessellation factors is:

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;
}

The hard-coded numeric constants are part of my debugging reduction. The commented-out line: "//return pow(..." is the original code, which I've replaced by the line that now follows.

With this replacement the tessellation is completely stable and reduces with distance from the camera. As expected, the reduction is only linear rather than logarithmic, but at least it works, is nicely tessellated and shows no signs of flicker.

With the original code, the mesh appeared to be switching at frame rate between apparently random tessellation factors.

Can anyone suggest what might be going wrong?

My patch constant function is:

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;
}

Upvotes: 0

Views: 734

Answers (1)

ErnieDingo
ErnieDingo

Reputation: 444

Looking at your return value. Looks like you are doing your tesselation backwards. Uncomment the price of code. Hard code the distance value say to say 1000. You should get a consistent tesselation. If you do then you should get no flickering. If you don't then its something with the power function as you assert or out not then your distance vectors are funky.

Edit: Added my tessellation function for reference.

  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;
}

Upvotes: 1

Related Questions