I'm applying phong shading onto a single giant triangle, and I'd like the light's coordinates to coincide with the camera's coordinates in 3D space. In order to do this, whenever I update the camera's coordinates, I also update the light's coordinates. However, diffuse and specular lighting don't "focus" exactly at the camera position when I bring the camera close to the triangle, instead they do it a few units too far. The triangle is .5 units below the XZ plane and parallel to it. Here is a picture demonstrating this effect.
Also, here are my HLSL shaders; this is where all the transformations happen.
// Vertex Shader ////////////////////////////////////////
float4x4 Matrix; // ViewProjection Matrix
float4x4 Matrix2; // View matrix
float4x4 Matrix3; // View matrix with translation zeroed out
float4 lightPos;
struct VS_INPUT
{
float4 Pos : POSITION;
float4 Normal : NORMAL;
float2 Tex0 : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Normal : TEXCOORD1;
float4 LightDir : TEXCOORD2;
float2 Tex0 : TEXCOORD0;
};
////////////////////////////////////////
VS_OUTPUT VShade(VS_INPUT In)
{
VS_OUTPUT Out = (VS_OUTPUT) 0;
Out.Tex0 = In.Tex0;
//world space -> clip space transformation
Out.Pos = mul(In.Pos, Matrix);
// world space -> camera space transformations
Out.Normal = normalize(mul(In.Normal, Matrix3));
Out.LightDir = normalize(mul(lightPos - In.Pos, Matrix3));
return Out;
}
// Pixel Shader ////////////////////////////////////////
sampler baseTex;
struct PS_INPUT
{
float4 LightDir : TEXCOORD2;
float4 Normal : TEXCOORD1;
float2 Tex0 : TEXCOORD0;
};
struct PS_OUTPUT
{
float4 Color : COLOR;
};
////////////////////////////////////////
PS_OUTPUT PShade(PS_INPUT In)
{
PS_OUTPUT Out = (PS_OUTPUT) 0;
float4 Normal = normalize(In.Normal);
float4 LightDir = normalize(In.LightDir);
float di = saturate(dot(Normal, LightDir));
float4 ambient = {0.1, 0.1, 0.1, 1};
float4 Reflect = normalize(2 * di * Normal - LightDir);
float specular = pow(saturate(dot(Reflect, LightDir)), 2);
Out.Color = ambient + tex2D(baseTex,In.Tex0) * di + specular;
return Out;
}
EDIT
In.LightDir is computed for each pixel. It is first computed for each vertex in the vertex shader Out.LightDir = normalize(mul(lightPos - In.Pos, Matrix3));, then it is interpolated across the whole triangle. lightPos is just the camera's position (which coincides with the light):
if(handle = m_pVertexConstants->GetConstantByName(NULL,"lightPos"))
m_pVertexConstants->SetVector(pDevice,handle,(D3DXVECTOR4*)m_camera.GetPosition());
Also, the world transformation matrix is just the identity, so I have not included it anywhere.