
Right now it just does point lights and there's no attenuation, but I plan on adding attenuation and support for all the different light types. What do you guys think of it?
I'm having one issue though. Sometimes when moving the camera (it's just an FPS camera), the teapot goes black for a single frame. Does anyone with shader experience know why this might occur? My assumption is that it has to do with the engine reordering the lights, but I don't know why that would make it go black for a second, and the lights are all fixed. Here are my callbacks:
EDIT: I've confirmed that the material drops to black for a second is when the lights reorder due to camera position change, but why would this affect the shader?
Code: Select all
void DirectionalPhong::OnSetConstants(IMaterialRendererServices *services, s32 userData)
{
worldViewProjection = vd->getTransform(video::ETS_PROJECTION);
worldViewProjection *= vd->getTransform(video::ETS_VIEW);
worldViewProjection *= vd->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant("worldViewProjection", worldViewProjection.pointer(), 16);
world = vd->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant("world", world.pointer(), 16);
world.getTransposed(worldTranspose);
worldTranspose.getInverse(worldInverseTranspose);
services->setVertexShaderConstant("worldInverseTranspose", worldInverseTranspose.pointer(), 16);
vd->getTransform(video::ETS_VIEW).getInverse(viewInverse);
services->setVertexShaderConstant("viewInverse", viewInverse.pointer(), 16);
s32 numLights = vd->getDynamicLightCount();
for(s32 c = 0; c < 5; c++)
{
numChar = '0' + c;
ltBuff[10] = numChar;
if(c >= numLights)
{
services->setPixelShaderConstant(ltBuff, (f32*)&kNoLight, 1);
continue;
}
light = vd->getDynamicLight(c);
switch(light.Type)
{
case(video::ELT_POINT):
lightType = 1;
break;
case(video::ELT_DIRECTIONAL):
lightType = 2;
break;
case(video::ELT_SPOT):
lightType = 3;
}
services->setPixelShaderConstant(ltBuff, (f32*)&lightType, 1);
arr[0] = light.Position.X;
arr[1] = light.Position.Y;
arr[2] = light.Position.Z;
lpBuff[14] = numChar;
services->setVertexShaderConstant(lpBuff, arr, 3);
arr[0] = light.AmbientColor.r;
arr[1] = light.AmbientColor.g;
arr[2] = light.AmbientColor.b;
acBuff[13] = numChar;
services->setPixelShaderConstant(acBuff, arr, 3);
arr[0] = light.DiffuseColor.r;
arr[1] = light.DiffuseColor.g;
arr[2] = light.DiffuseColor.b;
dcBuff[13] = numChar;
services->setPixelShaderConstant(dcBuff, arr, 3);
arr[0] = light.SpecularColor.r;
arr[1] = light.SpecularColor.g;
arr[2] = light.SpecularColor.b;
scBuff[14] = numChar;
services->setPixelShaderConstant(scBuff, arr, 3);
}
services->setPixelShaderConstant("specularAmount",
&specularAmount, 1);
services->setPixelShaderConstant("specularExponent",
&specularExponent, 1);
}
void DirectionalPhong::OnSetMaterial(const SMaterial& mat)
{
specularAmount = mat.Shininess;
specularExponent = mat.MaterialTypeParam;
}
Code: Select all
//Transform vertices to world space
float4x4 world;
//Transform normals to world space
float4x4 worldInverseTranspose;
//transform view coordinates to world space
float4x4 viewInverse;
//Transform coordinates to screen space
float4x4 worldViewProjection;
struct VertexInput
{
float3 position: POSITION;
float4 normal : NORMAL;
float4 uv : TEXCOORD0;
float4 color : COLOR0;
};
struct VertexOutput
{
float4 screenPos : POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float3 worldView : TEXCOORD2;
float3 lightVector[5] : TEXCOORD3;
float4 color : COLOR0;
};
float3 lightPosition[5];
VertexOutput ColorPhongVS(VertexInput IN)
{
VertexOutput OUT = (VertexOutput)0;
OUT.worldNormal = mul(IN.normal, worldInverseTranspose).xyz;
float4 worldPosition = mul(float4(IN.position.xyz, 1), world);
int c;
for(c = 0; c < 5; c++)
{
//Even if there aren't 5 valid lights, we'll just ignore the invalid ones
//In the pixel shader
OUT.lightVector[c] = lightPosition[c] - worldPosition.xyz;
}
OUT.worldView = normalize(viewInverse[3].xyz - worldPosition.xyz);
OUT.screenPos = mul(float4(IN.position, 1), worldViewProjection);
OUT.color = IN.color;
OUT.uv = IN.uv.xy;
return OUT;
}
float3 ambientColor[5];
float3 diffuseColor[5];
float3 specularColor[5];
//Types: Off (0), point (1), directional (2), spot(3)
int lightType[5];
float specularAmount;
float specularExponent;
float4 ColorPhongPS(VertexOutput IN) : COLOR
{
float3 lightVec;
float3 view = normalize(IN.worldView);
float3 norm = normalize(IN.worldNormal);
float3 halfAngle;
float4 litResult;
float3 diffuseContrib;
float3 specularContrib;
float4 matDiffuse = IN.color;
float4 OUT = float4(0, 0, 0, 1);
int c;
for(c = 0; c < 5; c++)
{
if(lightType[c] > 0)
{
lightVec = normalize(IN.lightVector[c]);
halfAngle = normalize(view + lightVec);
litResult = lit(dot(lightVec, norm),
dot(halfAngle, norm), specularExponent);
diffuseContrib = litResult.y * diffuseColor[c];
specularContrib = litResult.y * litResult.z *
specularAmount * specularColor[c];
OUT += float4(specularContrib +
(matDiffuse * (diffuseContrib + ambientColor[c])), 0);
}
}
OUT.a = matDiffuse.a;
OUT = saturate(OUT);
return OUT;
}