Hi All, I have a question. Why A Geometry Shader shows an incorrect Normals with using tessellation?
I see a line position for normals without Height, but height is reading from HeightMap's texture from DomainShader.
Vertex shader:
struct Output {
float4 pos : SV_POSITION;
location(1) float3 Normal : NORMAL;
};
struct Input {
float4 pos: SV_POSITION;
float3 Normal : NORMAL;
};
Output vsMain(in Input input) {
Output output;
output.pos = float4(input.pos.xyz, 1.0f);
output.Normal = input.Normal;
return output;
}
Hull Shader:
#define MAX_TF 20.0f
struct VSHSOutput {
float4 pos: SV_POSITION;
float3 Normal : NORMAL;
};
struct ConstantsHSOutput {
float Edges[4] : SV_TessFactor;
float Inside[2] : SV_InsideTessFactor;
};
cbuffer b0: register(b0) {
row_major float4x4 view;
row_major float4x4 proj;
float4 cameraPosition;
float LodDistance;
float tessellationFactor;
float tessellatedEdgeSize;
uint numLods;
float2 viewportDim;
};
float distSq(float3 p0, float3 p1) {
float3 d = p0 - p1;
return dot(d, d);
}
float screenSpaceTessFactor(float4 p0, float4 p1) {
float4 midPoint = 0.5f * (p0 + p1);
float radius = distance(p0, p1) * 0.5f;
float4 v0 = mul(midPoint, view);
float4 clip0 = mul(float4(v0.x - radius, v0.yzw), proj);
float4 clip1 = mul(float4(v0.x + radius, v0.yzw), proj);
clip0 /= clip0.w;
clip1 /= clip1.w;
clip0.xy *= viewportDim;
clip1.xy *= viewportDim;
return max(distance(clip0, clip1) / tessellatedEdgeSize * tessellationFactor, 1.0f);
}
float CalculateTessFactor(float4 p0, float4 p1) {
return screenSpaceTessFactor(p0, p1);
}
ConstantsHSOutput ConstantsHS(InputPatch<VSHSOutput, 4> ip, uint PatchID : SV_PrimitiveID) {
ConstantsHSOutput Output;
Output.Edges[0] = CalculateTessFactor(ip[0].pos, ip[3].pos);
Output.Edges[1] = CalculateTessFactor(ip[1].pos, ip[0].pos);
Output.Edges[2] = CalculateTessFactor(ip[2].pos, ip[1].pos);
Output.Edges[3] = CalculateTessFactor(ip[3].pos, ip[2].pos);
Output.Inside[0] = lerp(Output.Edges[0], Output.Edges[3], 0.5f);
Output.Inside[1] = lerp(Output.Edges[1], Output.Edges[2], 0.5f);
return Output;
}
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantsHS")]
[maxtessfactor(MAX_TF)]
VSHSOutput hMain(InputPatch<VSHSOutput, 4> ip, uint i : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID) {
VSHSOutput Output;
Output.pos = float4(ip[i].pos.xyz, 1.0f);
Output.Normal = ip[i].Normal;
return Output;
}
Domain Shader:
struct ConstantsHSOutput {
float Edges[4] : SV_TessFactor;
float Inside[2] : SV_InsideTessFactor;
};
struct InputOutput {
float4 pos: SV_POSITION;
float3 Normal : NORMAL;
};
cbuffer b0: register(b0) {
row_major float4x4 ViewProjection;
row_major float4x4 proj;
float4 cameraPosition;
float scaleHeight;
float2 uvScale;
};
Texture2D HeightMap : register(t0);
SamplerState Sampler : register(s0);
[domain("quad")]
InputOutput dMain(in ConstantsHSOutput input, float2 domain : SV_DomainLocation, const OutputPatch<InputOutput, 4> patch) {
InputOutput Output;
float4 pos = lerp(lerp(patch[0].pos, patch[1].pos, domain.x), lerp(patch[3].pos, patch[2].pos, domain.x), domain.y);
float2 uv = pos.xz * uvScale;
pos.y = HeightMap.SampleLevel(Sampler, uv, 0.0).r * scaleHeight;
Output.pos = float4(pos.xyz, 1.0f);
Output.Normal = lerp(lerp(patch[0].Normal, patch[1].Normal, domain.x), lerp(patch[3].Normal, patch[2].Normal, domain.x), domain.y);
return Output;
}
Geometry Shader:
struct GSIn {
float4 pos : POSITION;
float3 normal : NORMAL;
};
struct GSOut {
float4 pos : SV_POSITION;
float4 color : COLOR;
};
cbuffer b0: register(b0) {
row_major float4x4 ViewProjection;
};
[maxvertexcount(6)]
void gsMain(triangle GSIn Triangle[3], inout LineStream<GSOut> normal) {
const float4 color = float4(1.0f, 0.0f, 0.0f, 1.0f);
GSOut p;
p.color = color;
for (int i = 0; i < 3; ++i) {
p.pos = mul(float4(Triangle[i].pos.xyz, 1.0f), ViewProjection);
normal.Append(p);
p.pos.xyz = Triangle[i].pos.xyz + 5.0f * Triangle[i].normal;
p.pos = mul(float4(p.pos.xyz, 1.0f), ViewProjection);
normal.Append(p);
normal.RestartStrip();
}
}