vprat 122 Report post Posted November 9, 2009 Hi, I am currently implementing per pixel phong shading + normal mapping using DX10 and HLSL. I have the diffuse + normal map component working, but I am having problems with the specular component. First a picture of my result: As you can see, the specular result is as if the viewer or the light was on the left side of the cube. The diffuse result shows what is correct. As my diffuse-only result is fine, I assume the tangent space calculations are correct (maybe I am wrong). So I am left with a problem most probably with the reflection vector calculation or the view vector calculation. Below is the relevant code for the sample. I have generated a cube (but have same results with sphere and plane) where the front face (-z as normal) is generated like this: // Normal is -Z axis // Tangent is X axis // Tangent.w is -1 so that the binormal is correct //-- pVertex->vPosition = CVector3( fWidth * ( u - 0.5f ), fHeight * ( v - 0.5f ), -0.5f * fDepth ); pVertex->vNormal = CVector3( 0.0f, 0.0f, -1.0f ); pVertex->vTangent = CVector4( 1.0f, 0.0f, 0.0f, -1.0f ); pVertex->vTexCoord = CVector2( u, 1.0f - v ); My vertex shader is the following: VS_OUTPUT output = (VS_OUTPUT) 0; // Some vectors in world space //-- float4 P = mul( float4( input.position, 1), kgfx_matWorld ); // Position in world space float3 L = normalize( kgfx_vLightPosition.xyz - P.xyz ); // Light in world space float3 V = normalize( kgfx_vCameraPosition.xyz - P.xyz ); // View in world space // Build world to tangent space transformation //-- float3 T = normalize( mul( input.tangent, (float3x3) kgfx_matWorld ) ); float3 N = normalize( mul( input.normal, (float3x3) kgfx_matWorld ) ); float3 B = normalize( input.tangent.w * cross( N, T ) ); float3x3 TBN; TBN[0] = T; TBN[1] = B; TBN[2] = N; // Build the output //-- output.position = mul( P, kgfx_matViewProj ); // Position in screen space output.texCoord = input.texCoord; // Copy tex coords output.light = normalize( mul( TBN, L ) ); // Light in texture space output.view = normalize( mul( TBN, V ) ); // View in texture space return output; My pixel shader is the following: float3 L = normalize( input.light ); // Light in tangent space float3 V = normalize( input.view ); // View in tangent space float3 N = float3( 0, 0, 1 ); // Default normal in tangent space to compute self shadowing float fSelfShadow = dot( N, L ); if ( fSelfShadow>=0 ) { // Get normal from normal map //-- N = normalize( 2.0 * kgfx_texNormalMap.Sample( linearSampler, input.texCoord ) - 1.0 ); } fSelfShadow = saturate( 10 * fSelfShadow ); // Light reflection vector //-- float3 R = normalize( reflect( L, N ) ); float fSpecular = pow( saturate( dot( R, V ) ), 60 ); float fDiffuse = saturate( dot( N, L ) ); float4 colColor = kgfx_texColorMap.Sample( linearSampler, input.texCoord ); output.color = fSelfShadow * ( fDiffuse * colColor + fSpecular * kgfx_colLightColor ); 0 Share this post Link to post Share on other sites
knighty 313 Report post Posted November 12, 2009 Looks like the reflected vector is upside down.In your fragment shader try :float3 R = - reflect( L, N ) ;//No need to normalize because L and N are already normalized.Instead of:float3 R = normalize( reflect( L, N ) );You can also remove some normalizations. There are too many :) 0 Share this post Link to post Share on other sites
vprat 122 Report post Posted November 12, 2009 Hi,First of all, thanks a lot for your input.It works indeed when inverting the reflection vector. Why is this vector inverted? I have never seen in the other tutorials any -reflect( L, N ). Is it a problem with my tangent space calculations?Also, the shader works well without any normal mapping (N = 0, 0, 1) but not any more when I fetch the normal from the normal map.The normal map texture is created in the format R8G8B8A8_UNORM and is a normal map taken from blender I think so should be a valid file. 0 Share this post Link to post Share on other sites
knighty 313 Report post Posted November 12, 2009 Quote:Original post by vpratIt works indeed when inverting the reflection vector. Why is this vector inverted? I have never seen in the other tutorials any -reflect( L, N ). Is it a problem with my tangent space calculations?In this tutorial the reflected vector is calculated like this: float D = saturate(dot(N, LightDir)); float3 R = normalize(2 * D * N - LightDir); // Rwhich is equivalent (beside the saturation of dot(N,LightDir)) to:R = normalize(- reflect(LightDir,N));(see the definition of the reflect() function)This is what is happening according to the code of your OP :--------------------------------------As I said before, you really don't need to do as much normalizations. Try to remove all normalize() calls in your vertex shader and see what happens. 0 Share this post Link to post Share on other sites
vprat 122 Report post Posted November 13, 2009 Hi,I got it working properly. One thing was the reflect vector being inverted. Other thing was that in my sampling of the normal map I had a float being implicitly casted to a float3 but not as expected so the line:N = normalize( 2.0 * kgfx_texNormalMap.Sample( linearSampler, input.texCoord ) - 1.0 );was corrected into:N = normalize( 2.0 * kgfx_texNormalMap.Sample( linearSampler, input.texCoord ) - float3( 1, 1, 1 ) );I also removed most normalisation from the VS and some from the PS and took a normal map in the PNG format (JPEG showed the compression artifacts).Thanks a lot for helping, very appreciated.For those who could be interested, here is the final code://----------------------------------------------------------------------------// Types //----------------------------------------------------------------------------struct VS_INPUT{ float3 position : POSITION; float3 normal : NORMAL; float2 texCoord : TEXCOORD0; float4 tangent : TANGENT;};struct VS_OUTPUT{ float4 position : SV_POSITION; float2 texCoord : TEXCOORD0; float3 view : TEXCOORD1; float3 light : TEXCOORD2;};struct PS_OUTPUT{ float4 color : SV_TARGET;};//----------------------------------------------------------------------------// Shaders //----------------------------------------------------------------------------VS_OUTPUT myVertexShader( VS_INPUT input, uniform bool bWireframe = false ){ VS_OUTPUT output = (VS_OUTPUT) 0; // Some vectors in world space //-- float4 P = mul( float4( input.position, 1), kgfx_matWorld ); // Position in world space float3 L = kgfx_vLightPosition.xyz - P.xyz; // Light in world space float3 V = kgfx_vCameraPosition.xyz - P.xyz; // View in world space float3 T = mul( input.tangent, (float3x3) kgfx_matWorld ); float3 N = mul( input.normal, (float3x3) kgfx_matWorld ); float3 B = input.tangent.w * cross( N, T ); // Built the TBN matrix (world to texture space transform) //-- float3x3 TBN; TBN[0] = T; TBN[1] = B; TBN[2] = N; output.position = mul( P, kgfx_matViewProj ); // Position in screen space output.texCoord = input.texCoord; // Copy tex coords output.light = mul( TBN, L ); // Light in texture space output.view = mul( TBN, V ); // View in texture space return output;}PS_OUTPUT myPixelShader( VS_OUTPUT input, uniform bool bWireframe = false ){ PS_OUTPUT output = (PS_OUTPUT) 0; // Compute pixel value //-- if ( bWireframe ) { output.color = kgfx_colColor; } else { float3 L = normalize( input.light ); float3 V = normalize( input.view ); float3 N = float3( 0, 0, 1 ); float fSelfShadow = dot( N, L ); if ( kgfx_bUseNormalMap>0 && fSelfShadow>=0 ) { N = normalize( 2.0 * kgfx_texNormalMap.Sample( linearSampler, input.texCoord ) - float3( 1, 1, 1 ) ); } fSelfShadow = saturate( 10 * fSelfShadow ); float3 R = reflect( -L, N ); float fSpecular = pow( saturate( dot( R, V ) ), 60 ); float fDiffuse = saturate( dot( N, L ) ); float4 colColor = kgfx_bUseColorMap<=0 ? kgfx_colColor : kgfx_texColorMap.Sample( linearSampler, input.texCoord ); output.color.rgb = fSelfShadow * ( fDiffuse * colColor.rgb + fSpecular * kgfx_colLightColor.rgb ); output.color.a = colColor.a; } return output;} 0 Share this post Link to post Share on other sites