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!