Search code examples
3dshaderhlsldirect3ddirect3d11

Why aren't my Hull and Domain shaders compiling?


This is my Hull Shader, I get "warning X3554: unknown attribute <attr_name_here>, or attribute invalid for this statement" on every attribute above the main function, as well as "error X3658: 'main': InputPatch inputs can only be used in the domain shaders and a hull shader's patch constant function" on the InputPatch parameter in the main function:

struct HullShaderInput
{
    float4 wPos : WPOSITION;
    float4 position : SV_POSITION;
    float3 colour : COLOUR;
    float3 normal : NORMAL;
    float2 uv : UV;
};

struct HullShaderConstDataOutput
{
    float EdgeTessFactor[3] : SV_TessFactor;
    float InsideTessFactor : SV_InsideTessFactor;
};

struct HullShaderOutput
{
    float4 wPos : WPOSITION;
    float4 position : SV_POSITION;
    float3 colour : COLOUR;
    float3 normal : NORMAL;
    float2 uv : UV;
};

cbuffer cBuff : register(b0)
{
    float4x4 world;
    float4x4 view;
    float4x4 projection;
    float4 camPos;
}

//cbuffer iBuff : register(b1)
//{
//  float4 objPos;
//}

#define NUM_CONTROL_POINTS 3

float calcTessFactor(float3 vertP1, float3 vertP2)
{
    float edgeLen = distance(vertP1, vertP2);
    float edgeCamDist = distance((vertP1+vertP2)/2, camPos.xyz);
    
    // Not based on objects size on the screen
    // To give more accurate approximation, multiply with the screen height in pixels and an FOV factor (1 at 90 deg, increasing at lower FOV),
    //and divide by the allowed edge length in pixels.
    return clamp((edgeLen)/(edgeCamDist), 1.0f, 63.0f); // Using max=63 because of fractional_odd partitioning
}

HullShaderConstDataOutput CalcHSPatchConstants
(   InputPatch<HullShaderInput, NUM_CONTROL_POINTS> ip,
    uint i : SV_PrimitiveID )
{
    HullShaderConstDataOutput output;
    // This function should calculate the factors based on distance to camera, so the constant value is just temporary... I think
    //output.EdgeTessFactor[0] = output.EdgeTessFactor[1] = output.EdgeTessFactor[2] = output.InsideTessFactor = 32;
    // Anyways, this should have a decent approximation for realistic tessellation factors based on distance to camera
    // That is, if every "ip" represents a triangle, and "i" represents a point on said triangle
    output.EdgeTessFactor[i] = calcTessFactor(ip[i].wPos.xyz, ip[(i+1)%3].wPos.xyz);
    output.InsideTessFactor = (output.EdgeTessFactor[0]+output.EdgeTessFactor[1]+output.EdgeTessFactor[2])/3;

    return output;
}

[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("HullShaderConstDataOutput")]
HullShaderOutput main
(   InputPatch<HullShaderInput, NUM_CONTROL_POINTS> ip,
    uint i : SV_OutputControlPointID    )
{
    HullShaderOutput output;
    
    output.wPos = ip[i].wPos;
    output.position = ip[i].position;
    output.normal = ip[i].normal;
    output.uv = ip[i].uv;
    
    return output;
}

This is my Domain Shader, I get "warning X3554" on [domain("tri")] and "error X3658" on on the main function's OutputPatch parameter:

struct DomainShaderConstDataInput
{
    float EdgeTessFactor[3] : SV_TessFactor;
    float InsideTessFactor : SV_InsideTessFactor;
};

struct DomainShaderInput
{
    float4 wPos : WPOSITION;
    float4 position : SV_POSITION;
    float3 colour : COLOUR;
    float3 normal : NORMAL;
    float2 uv : UV;
};

struct DomainShaderOutput
{
    float4 wPos : WPOSITION;
    float4 position : SV_POSITION;
    float3 colour : COLOUR;
    float3 normal : NORMAL;
    float2 uv : UV;
};

cbuffer cBuff : register(b0)
{
    float4x4 world;
    float4x4 view;
    float4x4 projection;
    float4 camPos;
};

#define NUM_CONTROL_POINTS 3

[domain("tri")]
DomainShaderOutput main
(   DomainShaderConstDataInput input, float3 barycentric : SV_DomainLocation,
    const OutputPatch<DomainShaderInput, NUM_CONTROL_POINTS> patch  )
{
    DomainShaderOutput output;
    output.wPos = patch[0].wPos*barycentric.x + patch[1].wPos*barycentric.y + patch[2].wPos*barycentric.z;
    output.normal = normalize(patch[0].normal*barycentric.x + patch[1].normal*barycentric.y + patch[2].normal*barycentric.z);
    output.uv = patch[0].uv*barycentric.x + patch[1].uv*barycentric.y + patch[2].uv*barycentric.z;
    output.position = mul(mul(output.wPos, view), projection);
    
    return output;
}

What am I doing wrong here?

Edit:

So, it turns out that my Hull and Domain shaders were using Shader Model 4, when 5 is required. Still, I can't compile them yet, because for some reason the HullShaderConstDataOutput attribute's entrypoint can't be found in the main function.


Solution

  • So, it turns out that my Hull and Domain shaders were using Shader Model 4, when 5 is required. It is now fixed. I also had the issue of referring to the constData struct and not the constData function, so that also sucks. Anyways, I can now render tessellated surfaces based on distance to the camera and the edge length for a fixed window size and FOV==90.