Search code examples
c++shaderdirectx

how to use tessellation in directx12?


I'm using directx12. I want to make tessellation for my polygon, for this I wrote 2 simple shaders:

struct Vertex{
    float3 Position : POSITION;
    float4 Color : COLOR;
};

struct tesOutput{
    float edgeTessellationFactor[3] : SV_TessFactor;
    float insideTessellationFactor : SV_InsideTessFactor;
};

tesOutput ConstantHS(InputPatch< Vertex, 3> patch, uint patchID : SV_PrimitiveID ){
    tesOutput output;
    output.edgeTessellationFactor[0] = 1.0f;
    output.edgeTessellationFactor[1] = 1.0f;
    output.edgeTessellationFactor[2] = 1.0f;
    output.insideTessellationFactor = 1.0f;
    return output;
}   

[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("ConstantHS")]
Vertex hull(InputPatch< Vertex, 3> patch, uint cPoint : SV_OutputControlPointID){
    return patch[cPoint];
}

struct DomainOut{
    float4 Position : SV_POSITION;
    float4 Color : COLOR;
};


[domain("tri")]
DomainOut domain(OutputPatch< Vertex, 3> patch, tesOutput tessInput, float3 UVW : SV_DomainLocation ){
    DomainOut output;
    
    float4 _1=float4(patch[0].Position.xyz,1);
    float4 _2=float4(patch[1].Position.xyz,1);
    float4 _3=float4(patch[2].Position.xyz,1);
    output.Position=_1 * UVW.x +
                    _2 * UVW.y +
                    _3 * UVW.z ;
    output.Position=float4(output.Position.xyz, 1.0f);

    output.Color = float4(1.0f, 0.0f, 1.0f, 1.0f);
        
    return output;
}

here are my vs and ps:

struct vertex{
    float3 pos : POSITION;
    float4 color : COLOR;
};

vertex main(float3 position : POSITION, float4 color : COLOR) {
    vertex output;
    output.pos = position;
    output.color = float4(1.0f, 0.0f, 1.0f, 1.0f);
    return output;
}

struct VS_OUTPUT
{
    float4 pos: SV_POSITION;
    float4 color: COLOR;
};

float4 main(VS_OUTPUT input) : SV_TARGET
{
    return input.color;
}

To understand the reason, I simplified the shaders as much as possible, I don’t even use the wvp matrix. If I use a vertex shader like this without tessellation, the polygon is rendered

struct vertex{
    float4 pos : SV_POSITION;
    float4 color : COLOR;
};

vertex main(float3 position : POSITION, float4 color : COLOR) {
    vertex output;
    output.pos = float4(position, 1);
    output.color = float4(1.0f, 0.0f, 1.0f, 1.0f);
    return output;
}

if i use my hs and ds the screen is blank. I don't understand why, because they don't do anything at all, because tesselation parameters are 1.0f. I've looked at all the shader examples I could find and I don't see any reason why my shaders aren't working. This is how I compile shaders:

D3DCompileFromFile(L"Shaders/VertexShader.hlsl", nullptr, nullptr, "main", "vs_5_0", D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &DX12.Shaders.vShader, &error)
D3DCompileFromFile(L"Shaders/TeselationShader.hlsl", nullptr, nullptr, "hull", "hs_5_0", D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &DX12.Shaders.hShader, &error)
D3DCompileFromFile(L"Shaders/TeselationShader.hlsl", nullptr, nullptr, "domain", "ds_5_0", D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &DX12.Shaders.dShader, &error)
D3DCompileFromFile(L"Shaders/ColorShader.hlsl", nullptr, nullptr, "main", "ps_5_0", D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &DX12.Shaders.pShader, &error)

here are some of the pipeline parameters that I changed to set hs and ds:

pipeLineDesc.VS={DX12.Shaders.vShader->GetBufferPointer(), DX12.Shaders.vShader->GetBufferSize()};
pipeLineDesc.PS={DX12.Shaders.cShader->GetBufferPointer(), DX12.Shaders.cShader->GetBufferSize()};
pipeLineDesc.HS={DX12.Shaders.hShader->GetBufferPointer(), DX12.Shaders.hShader->GetBufferSize()};
pipeLineDesc.DS={DX12.Shaders.dShader->GetBufferPointer(), DX12.Shaders.dShader->GetBufferSize()};
pipeLineDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
pipeLineDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH ;

I didn't do anything else in DirectX. Perhaps I need to do some extra work with DirectX to get my shaders to work, or my shaders are written incorrectly (I'm handling all errors, I just skipped that for code brevity)


Solution

  • The problem turned out to be that I had not completely changed the type topology. This is not reflected in the question text. To use tessellation you need to set

    D3D12_PRIMITIVE_TOPOLOGY_TYPE::D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH
    

    in the structure field

    D3D12_GRAPHICS_PIPELINE_STATE_DESC::PrimitiveTopologyType
    

    and also set

    ID3D12GraphicsCommandList::IASetPrimitiveTopology(D3D_PRIMITIVE_TOPO LOGY_3_CONTROL_POINT_PATCHLIST)