Instead of doing lighting in world space, we can transform the eye and light vector from world space into tangent space and do all the lighting calculations in that space. Modify the normal mapping shader to do the lighting calculations in tangent space.
so I edited the normalsampletoworldspace taking the transpose of the TBN matrix
float3 NormalSampleToWorldSpace(float3 normalMapSample, float3 unitNormalW, float3 tangentW)
{
// Uncompress each component from [0,1] to [-1,1].
float3 normalT = 2.0f*normalMapSample - 1.0f;
// 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 test = transpose(TBN);
// Transform from tangent space to world space.
float3 bumpedNormalW = mul(normalT, test);
return bumpedNormalW;
}
Also changed the toEye vector like
float3 toEye = bumpedNormalW2*(gEyePosW - pin.PosW);
so the transposed TBN TIMES toEye.
I also mulitiplied the lightvec by bumpedNormalW2. my images are showing up dark(the first one is without normal map, second is with normal map)
Is there anything else that needs to be done to make the lighting in tangent space. what seems to be the problem?
here is the orignianl shader code and then edited to make tangent space normal mapping
float4 PS(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);
// 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);
// Normalize.
toEye /= distToEye;
// 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);
}
}
//
// Normal mapping
//
float3 normalMapSample = gNormalMap.Sample(samLinear, pin.Tex).rgb;
float3 bumpedNormalW = NormalSampleToWorldSpace(normalMapSample, pin.NormalW, pin.TangentW);
//
// 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;
ComputeDirectionalLight(gMaterial, gDirLights[i], bumpedNormalW, toEye,
A, D, S);
ambient += A;
diffuse += D;
spec += S;
}
litColor = texColor*(ambient + diffuse) + spec;
if( gReflectionEnabled )
{
float3 incident = -toEye;
float3 reflectionVector = reflect(incident, bumpedNormalW);
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;
}
float4 PS(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);
float3 normalMapSample2 = gNormalMap.Sample(samLinear, pin.Tex).rgb;
float3 bumpedNormalW2 = NormalSampleToWorldSpace(normalMapSample2, pin.NormalW, pin.TangentW);
// The toEye vector is used in lighting.
float3 toEye = bumpedNormalW2*(gEyePosW - pin.PosW);
// Cache the distance to the eye from this surface point.
float distToEye = length(toEye);
// Normalize.
toEye /= distToEye;
// 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);
}
}
//
// Normal mapping
//
float3 normalMapSample = gNormalMap.Sample(samLinear, pin.Tex).rgb;
float3 bumpedNormalW = NormalSampleToWorldSpace(normalMapSample, pin.NormalW, pin.TangentW);
//
// 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;
ComputeDirectionalLight(gMaterial, gDirLights[i], bumpedNormalW, toEye,
A, D, S,bumpedNormalW);
ambient += A;
diffuse += D;
spec += S;
}
litColor = texColor*(ambient + diffuse) + spec;
if( gReflectionEnabled )
{
float3 incident = -toEye;
float3 reflectionVector = reflect(incident, bumpedNormalW);
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;
}