DirectX11 Tessellation not working

Started by
1 comment, last by RobM 2 years, 6 months ago

I've been implementing Tessellation into my DX11/C++ game engine and I can't seem to get it working. I've cross checked my shaders with almost every example I've found and they look ok. Running my engine in the Visual Studio Graphics Analyzer shows me that there is something a miss:

VS Graphics Analyzer showing no output from Pixel Shader and Hull/Domain shader unavailable

My Vertex, Hull and Domain shaders are extremely simple:

Vertex Shader:

struct VertexShaderInput
{
	float3 Position : SV_POSITION;
	float2 UV : TEXCOORD;
	float3 Normal : NORMAL;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

struct HullInputType
{
	float4 Position : SV_POSITION;
	float2 UV : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

HullInputType main(VertexShaderInput input)
{
	HullInputType output = (HullInputType)0;

	output.Position = float4(input.Position, 1.0);
	return output;
}

Hull Shader:


struct VertexShaderOutput
{
	float4 Position : SV_POSITION;
	float2 UV : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

struct HullOutputType
{
	float4 Position : SV_POSITION;
	float2 UV : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

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


[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantHS")]
[maxtessfactor(64.0)]
HullOutputType hullShader(InputPatch<VertexShaderOutput, 4> inputPatch, uint controlPointID : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID)
{
	HullOutputType output;

	// Copy inputs to outputs
	output.Position = inputPatch[controlPointID].Position;
	output.UV = inputPatch[controlPointID].UV;
	output.Normal = inputPatch[controlPointID].Normal;
	output.Tangent = inputPatch[controlPointID].Tangent;
	output.Binormal = inputPatch[controlPointID].Binormal;
	return output;
}

ConstantOutputType ConstantHS(InputPatch<VertexShaderOutput, 4> inputPatch, uint patchID : SV_PrimitiveID)
{
	ConstantOutputType output;
	float density = 4.0f;
	output.edges[0] = density;
	output.edges[1] = density;
	output.edges[2] = density;
	output.edges[3] = density;
	output.inside[0] = density;
	output.inside[1] = density;
	return output;
}

Domain Shader:

// the object buffer is updated for each draw call
cbuffer ObjectBuffer : register(b0)
{
	row_major matrix gWMatrix;
};

// the frame buffer is updated once per frame
cbuffer FrameBuffer : register(b1)
{
	row_major matrix gVPMatrix;
};

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

struct HullOutputType
{
	float4 Position : SV_POSITION;
	float2 UV : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

struct PixelInputType
{
	float4 Position : SV_POSITION;
	float2 UV : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
};

[domain("quad")]
PixelInputType domainShader(ConstantOutputType input, float2 domain : SV_DomainLocation, const OutputPatch<HullOutputType, 4> patch)
{
	PixelInputType output;

	// Determine the position of the new vertex.
	float3 worldPosition = lerp(
		lerp(patch[0].Position, patch[1].Position, domain.x),
		lerp(patch[2].Position, patch[3].Position, domain.x),
		domain.y);

	worldPosition = mul(float4(worldPosition, 1.0), gWMatrix);
	output.Position = mul(worldPosition, gVPMatrix);

	// Send the input color into the pixel shader.
	output.UV = patch[0].UV;
	output.Normal = lerp(
		lerp(patch[0].Normal, patch[1].Normal, domain.x),
		lerp(patch[2].Normal, patch[3].Normal, domain.x),
		domain.y);

	output.Tangent = lerp(
		lerp(patch[0].Tangent, patch[1].Tangent, domain.x),
		lerp(patch[2].Tangent, patch[3].Tangent, domain.x),
		domain.y);
	output.Binormal = lerp(
		lerp(patch[0].Binormal, patch[1].Binormal, domain.x),
		lerp(patch[2].Binormal, patch[3].Binormal, domain.x),
		domain.y);
	return output;
}

My pixel shader is more complex, but everything works fine without the Hull and Domain shaders. I'm setting everything correctly, the input layouts are right, the topology is correct, all the buffers are set correctly, in DX Debug mode, no errors are returned but for some reason I can't see the rendered object (it's a simple flat quad).

The Input/Output in the vertex shader look correct to me - I've removed all the normal and tangent/binormal code for brevity. The Input/Output for the Hull shader only shows the input:

Has anyone seen this behaviour before in the Graphics Analyzer? Or any tips on what I may have missed on tessellation? Everything looks the same as Rastertek, apart from the fact that I'm using SV_POSITION all the way through the pipeline, they use POSITION.

Advertisement

In case anyone is interested, I resolved this. It turns out that the SV_POSITION/POSITION semantics are important (at least for my AMD GPU). I got it to work by pushing SV_POSITION into the Vertex shader, outputting POSITION to the hull shader, POSITION to the domain shader, and SV_POSITION into the pixel shader. It's the only configuration that worked for me. A lot of the tutorials I've read don't seem to differentiate this and I haven't seen anything that explains it properly, but I think SV_POSITION appears to be the system value for pixel space positions. What I think was happening was when I outputted SV_POSITION to the hull shader, it was mangling the values into pixel space and just not drawing correctly.

Anyway, onwards and upwards…

This topic is closed to new replies.

Advertisement