The models in my game are instanced to reduce draw calls, which basically means I'm passing in a 4x4 transform as part of a custom vertex definition. I am trying to get basic lighting working but can't seem to get the normals calculations working. It seems that no matter what I try, only the top of models are lit, regardless of the position of the sun.
Furthermore, I also can't get any of the lights other than the sun to even show up. I'm thinking I'm maybe missing a transform somewhere.
float4x4 World;
float4x4 View;
float4x4 Projection;
#define MAXLIGHT 20
float3 PointLightPosition[MAXLIGHT];
float4 PointLightColor[MAXLIGHT];
float PointLightIntensity[MAXLIGHT];
float PointLightRadius[MAXLIGHT];
int MaxLightsRendered = 0;
struct VS_MODEL_ShaderInput
{
float4 Position : SV_Position;
float4 Color : COLOR;
float2 TexCoord : TEXCOORD0;
float3 Normal : NORMAL;
};
struct VertexShaderOutput
{
float4 Position : SV_Position;
float4 WorldPosition : COLOR1;
float3 Normal : TEXCOORD1;
float2 TexCoord : TEXCOORD0;
float4 Color : COLOR;
};
float4 CalcDiffuseLight(float3 normal, float3 lightDirection, float4 lightColor, float lightIntensity)
{
return saturate(dot(normal, -lightDirection)) * lightIntensity * lightColor;
}
float4 CalcSpecularLight(float3 normal, float3 lightDirection, float3 cameraDirection, float4 lightColor, float lightIntensity)
{
float3 halfVector = normalize(-lightDirection + -cameraDirection);
float specular = saturate(dot(halfVector, normal));
//I have all models be the same reflectance
float specularPower = 20;
return lightIntensity * lightColor * pow(abs(specular), specularPower);
}
// The squared length of a vector
float lengthSquared(float3 v1)
{
return v1.x * v1.x + v1.y * v1.y + v1.z * v1.z;
}
float3 CameraPosition;
float3 SunLightDirection;
float4 SunLightColor;
float SunLightIntensity;
Texture2D Texture;
sampler textureSampler = sampler_state
{
Texture = <Texture>;
MinFilter = linear;
MagFilter = Anisotropic;
AddressU = Wrap;
AddressV = Wrap;
};
VertexShaderOutput Model_InstancingVS(VS_MODEL_ShaderInput input, float4x4 instanceTransform : BLENDWEIGHT)
{
instanceTransform = mul(World, transpose(instanceTransform));
VertexShaderOutput output;
// Apply the world and camera matrices to compute the output position.
float4 worldPosition = mul(input.Position, instanceTransform);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.WorldPosition = (float4) worldPosition;
output.Normal = normalize(mul(input.Normal, (float3x3) instanceTransform));
// Compute lighting, using a simple Lambert model.
output.Color = input.Color;
// Copy across the input texture coordinate.
output.TexCoord = input.TexCoord;
return output;
}
float4 MainPS(VertexShaderOutput input) : COLOR0
{
float4 outColor = tex2D(textureSampler, input.TexCoord); // * output.Color;
float4 diffuseLight = float4(0, 0, 0, 0);
float4 specularLight = float4(0, 0, 0, 0);
float4 diffuseSpecular = float4(0, 0, 0, 0);
float3 cameraDirection = normalize((float3) input.WorldPosition - CameraPosition);
diffuseLight += CalcDiffuseLight(input.Normal, SunLightDirection, SunLightColor, SunLightIntensity);
diffuseSpecular += CalcSpecularLight(input.Normal, SunLightDirection, cameraDirection, SunLightColor, SunLightIntensity);
//return outColor;
////calculate our pointLights
[loop]
for (int i = 0; i < MaxLightsRendered; i++)
{
float3 PointLightDirection = (float3) input.WorldPosition - PointLightPosition[i];
float DistanceSq = lengthSquared(PointLightDirection);
float radius = PointLightRadius[i];
[branch]
if (DistanceSq < abs(radius * radius))
{
float Distance = sqrt(DistanceSq);
PointLightDirection /= Distance;
float du = Distance / (1.0 - DistanceSq / (radius * radius - 1));
float denom = du / abs(radius) + 1.0;
//The attenuation is the falloff of the light depending on distance basically
float attenuation = 1.0 / (denom * denom);
diffuseLight += CalcDiffuseLight(input.Normal, PointLightDirection, PointLightColor[i], PointLightIntensity[i]) * attenuation;
specularLight += CalcSpecularLight(input.Normal, PointLightDirection, cameraDirection, PointLightColor[i], PointLightIntensity[i]) * attenuation;
}
}
return outColor * diffuseLight * diffuseSpecular;
}
technique ModelInstancing
{
pass P0
{
VertexShader = compile vs_3_0 Model_InstancingVS();
PixelShader = compile PS_SHADERMODEL MainPS();
}
};
If anyone can spot anything or give me a shove in the right direction I'd really appreciate it.
diffuseLight * diffuseSpecular needed to be addition:
diffuseLight + diffuseSpecular