Original Post
I'm writing a simple graphics program using DirectX 10 (though the Direct3D version shouldn't matter as far as my problem is concerned). My program can successfully display 3D models on screen using vertex and pixel shaders (written in HLSL). My problem is that no matter what I do, I can't seem to transform my models' normal vectors to make the lighting calculations work properly. My test model is a simple textured cube and I know that the initial vertex normals are correct. I also know that my transformation matrices are correct as I can successfully translate and rotate the cube. When it comes to transforming the normals, however, nothing seems to work. I've tried using the same world transformation matrix as the vertices; it didn't work. I've tried using the inverse transpose world matrix (as well as the transpose inverse world matrix); it didn't work. I know it must be the transformed normals because when I try lighting the cube without moving it around first, the lighting model appears to shade the cube in an expected way. Here is the relevent code: Calculating the transpose inverse world matrix (I've tried it the other way too) Shader code: EDIT: Please remember to use 'source' tags in future. [Edited by - jollyjeffers on January 14, 2008 5:21:56 AM]
D3DXMATRIX invmat;
D3DXMATRIX transpose;
D3DXMatrixTranspose(&transpose, &transformation.trans);
D3DXMatrixInverse(&invmat,NULL,&transpose);
//D3DXMatrixInverse(&invmat,NULL,&transformation.trans);
//D3DXMatrixTranspose(&transpose, &invmat);
r_elem->invworld->SetMatrix((float*)&invmat);
//constant buffer of external variables
cbuffer variables
{
matrix Projection;
matrix View;
matrix World;
matrix InvWorld;
float Specular_exponent;
float3 Specular;
float3 Emissive;
float3 local_light_pos;
float local_light_radius;
float3 local_light_color;
};
extern Texture2D EmissiveTexture;
extern Texture2D BumpmapTexture;
extern Texture2D DiffuseTexture;
extern Texture2D SpecularTexture;
extern Texture2D TransparencyTexture;
float3x3 TBNMatrix;
float3 color = float3(1.0f, 0.0f, 0.0f);
//PS_INPUT - input variables to the pixel shader
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
float3 Normal : TEXCOORD1;
float4 Orig_Pos : TEXCOORD2;
float3 LightDir : TEXCOORD3;
};
//texture sampler
SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
//attenuation function (no bump-mapping)
float Attenuation(float3 LightPos, float3 Pos3D, float light_radius)
{
float distance = distance(LightPos, Pos3D);
distance = distance * (1 / light_radius);
float atten = 1 / (distance + (distance * distance));
return atten;
}
//test vertex shader
PS_INPUT test_vs(float4 Pos : POSITION, float2 Tex : TEXCOORD0, float3 Normal : NORMAL, float3 tangent : TANGENT, float3 bitangent : BITANGENT)
{
PS_INPUT psInput;
float4x4 WorldView = mul(World, View);
float4x4 WorldViewProj = mul(WorldView, Projection);
psInput.Pos = mul(Pos, WorldViewProj);
psInput.Orig_Pos = mul(Pos, World);
psInput.Tex = Tex;
psInput.Normal = mul(InvWorld, float4(Normal,0.0f)).xyz;
psInput.Normal = normalize(psInput.Normal);
psInput.LightDir = normalize(local_light_pos - psInput.Orig_Pos);
TBNMatrix = float3x3(tangent,bitangent,psInput.Normal);
return psInput;
}
//test pixel shader
float4 test_ps(PS_INPUT psInput) : SV_TARGET
{
float DiffuseLightingFactor = dot(psInput.LightDir, psInput.Normal);
float atten = Attenuation(local_light_pos, psInput.Orig_Pos, local_light_radius);
float4 outColor;
//outColor.rgb = DiffuseTexture.Sample(samLinear, psInput.Tex) * local_light_color * (1-DiffuseLightingFactor) * atten;
outColor.rgb = local_light_color * (1-DiffuseLightingFactor) * atten;
outColor.a = 1.0f;
return outColor;
}
//define a technique
technique10 Render
{
pass P0
{
SetVertexShader(CompileShader(vs_4_0, test_vs()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, test_ps()));
}
}