3

I'm trying to calculate lighting in tangent space. But I just keep getting abnormal results. I was modifying the book's demo code and I wander if there maybe something wrong with the transformation matrix I created.

I'm having trouble solving a problem in Introduction to 3D Game Programming with DirectX 11. I tried to use matrix TBN

Tx, Ty, Tz,
Bx, By, Bz,
Nx, Ny, Nz

as the book provided but I found the light vector to be wrongly transformed to tangent space and now I have no clue how to debug this shader.

Here is my Pixel Shader:

float4 PS1(VertexOut pin,
uniform int gLightCount,
uniform bool gUseTexure,
uniform bool gAlphaClip,
uniform bool gFogEnabled,
uniform bool gReflectionEnabled) : SV_Target{
// Interpolating normal can unnormalize it, so normalize it.
pin.NormalW = normalize(pin.NormalW);
pin.TangentW = normalize(pin.TangentW);

// The toEye vector is used in lighting.
float3 toEye = gEyePosW - pin.PosW;

// Cache the distance to the eye from this surface point.
float distToEye = length(toEye);

// Calculate normalMapSample
float3 normalMapSample = 
normalize(SampledNormal2Normal(gNormalMap.Sample(samLinear, pin.Tex).rgb));

// normalize toEye
toEye = normalize(toEye);

// Default to multiplicative identity.
float4 texColor = float4(1, 1, 1, 1);
if (gUseTexure)
{
    // Sample texture.
    texColor = gDiffuseMap.Sample(samLinear, pin.Tex);

    if (gAlphaClip)
    {
        // Discard pixel if texture alpha < 0.1.  Note that we do this
        // test as soon as possible so that we can potentially exit the shader 
        // early, thereby skipping the rest of the shader code.
        clip(texColor.a - 0.1f);
    }
}

//
// Lighting.
//

float4 litColor = texColor;
if (gLightCount > 0)
{
    // Start with a sum of zero. 
    float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
    float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
    float4 spec = float4(0.0f, 0.0f, 0.0f, 0.0f);

    // Sum the light contribution from each light source.  
    [unroll]
    for (int i = 0; i < gLightCount; ++i)
    {
        float4 A, D, S;
        ComputeDirectionalLightInTangent(gMaterial, gDirLights[i], 
            normalMapSample, World2TangentSpace(pin.NormalW, pin.TangentW, gTexTransform), toEye,
            A, D, S);

        ambient += A;
        diffuse += D;
        spec += S;
    }

    litColor = texColor*(ambient + diffuse) + spec;

    if (gReflectionEnabled)
    {
        float3 incident = -toEye;
        float3 reflectionVector = reflect(incident, normalMapSample);
        float4 reflectionColor = gCubeMap.Sample(samLinear, reflectionVector);

        litColor += gMaterial.Reflect*reflectionColor;
    }
}

//
// Fogging
//

if (gFogEnabled)
{
    float fogLerp = saturate((distToEye - gFogStart) / gFogRange);

    // Blend the fog color and the lit color.
    litColor = lerp(litColor, gFogColor, fogLerp);
}

// Common to take alpha from diffuse material and texture.
litColor.a = gMaterial.Diffuse.a * texColor.a;

return litColor;
}  

And Here are function SampledNormal2Normal, World2TangentSpace and ComputeDirectionalLightInTangent:

float3 SampledNormal2Normal(float3 sampledNormal)
{
float3 normalT = 2.0f*sampledNormal - 1.0f;
return normalT;
}

float3x3 World2TangentSpace(float3 unitNormalW, float3 tangentW, float4x4 texTransform)
{
// Build orthonormal basis.
float3 N = unitNormalW;
float3 T = normalize(tangentW - dot(tangentW, N)*N);
float3 B = cross(N, T);

float3x3 TBN = float3x3(T, B, N);
/*float3x3 invTBN = float3x3(T.x, T.y, T.z, B.x, B.y, B.z, N.x, N.y, N.z);
return invTBN;*/


float3 T_ = T - dot(N, T)*N;
float3 B_ = B - dot(N, B)*N - (dot(T_, B)*T_) / dot(T_, T_);
float3x3 invT_B_N = float3x3(T_.x, T_.y, T_.z, B_.x, B_.y, B_.z, N.x, N.y, N.z);
return invT_B_N;
}

void ComputeDirectionalLightInTangent(Material mat, DirectionalLight L,
float3 normalT, float3x3 toTS, float3 toEye,
out float4 ambient,
out float4 diffuse,
out float4 spec)
{
// Initialize outputs.
ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
spec = float4(0.0f, 0.0f, 0.0f, 0.0f);

// The light vector aims opposite the direction the light rays travel.
float3 lightVec = -L.Direction;
lightVec = mul(lightVec, toTS);
lightVec = normalize(lightVec);

// toEye to Tangent Space
toEye = mul(toEye, toTS);
toEye = normalize(toEye);

// Add ambient term.
ambient = mat.Ambient * L.Ambient;

// Add diffuse and specular term, provided the surface is in 
// the line of site of the light.

float diffuseFactor = dot(lightVec, normalT);

// Flatten to avoid dynamic branching.
[flatten]
if (diffuseFactor > 0.0f)
{
    float3 v = reflect(-lightVec, normalT);
    float specFactor = pow(max(dot(v, toEye), 0.0f), mat.Specular.w);

    diffuse = diffuseFactor * mat.Diffuse * L.Diffuse;
    spec = specFactor * mat.Specular * L.Specular;
}
}

The result I got seem to be much darker in most places and too bright in several highlight area. I wonder if anyone can help me with my code or give me advice on how to debug a hlsl shader. My thousand thanks!

tigerccx
  • 47
  • 6
  • You may want to post this on https://gamedev.stackexchange.com/ – auburg May 16 '19 at 07:56
  • Thx, I will check it out. – tigerccx May 16 '19 at 14:04
  • I would advice you to reduce your shader for the first steps to do only the minimum, so you can find errors more easily (remove fogging, ambient, specular, etc...) Then try to track down the error by checking the inputs and results of each step (rendering the normals as colors and look if they seems to be right and so on). Overshooting intensity sound for me as some not normalized vectors, but that's only a gut feeling :) For example your `T_ ` and `B_ ` will be shorter than a unit vector after the projection leading to an unwanted factor in the lighting computation. – Gnietschow May 20 '19 at 09:18

0 Answers0