float materialShininess;
const int NumberOfLights = 8;
varying vec3 N;
varying vec3 ecPosition3; // in 3 space
uniform bool LightsEnabled[NumberOfLights];
uniform int LightsType[NumberOfLights]; // 0 == directional, 1 == spot, 2 == point
void DirectionalLight(in int i,
in vec3 normal,
out vec4 ambient,
out vec4 diffuse,
out vec4 specular)
{
float nDotVP; // normal . light direction
float nDotHV; // normal. light half vector
float pf; // power factor
nDotVP = max(0.0, dot(normal, normalize(vec3(gl_LightSource[i].position))));
nDotHV = max(0.0, dot(normal, vec3(gl_LightSource[i].halfVector)));
if (nDotVP == 0.0)
pf = 0.0;
else
pf = pow(nDotHV, materialShininess);
ambient = gl_LightSource[i].ambient;
diffuse = clamp(gl_LightSource[i].diffuse * nDotVP, 0.0, 1.0);
specular = clamp (gl_LightSource[i].specular * pf, 0.0, 1.0);
}
void ComputeSpotPointParameters( in int i,
in vec3 eye,
in vec3 ecPosition3,
in vec3 normal,
out vec3 VP,
out float nDotVP,
out float pf,
out float attenuation)
{
float nDotHV;
float d;
vec3 halfVector;
VP = vec3(gl_LightSource[i].position) - ecPosition3;
d = length(VP);
VP = normalize(VP);
attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * d +
gl_LightSource[i].quadraticAttenuation *d * d);
halfVector = normalize(VP + eye);
nDotVP = max(0.0, dot(normal, VP));
nDotHV = max(0.0, dot(normal, halfVector));
if (nDotVP == 0.0)
pf = 0.0;
else
pf = pow(nDotHV, gl_FrontMaterial.shininess);
}
void SpotLight(in int i,
in vec3 eye,
in vec3 ecPosition3,
in vec3 normal,
inout vec4 ambient,
inout vec4 diffuse,
inout vec4 specular)
{
vec3 VP;
float nDotVP, pf;
float spotAttenuation;
float attenuation;
ComputeSpotPointParameters( i,
eye,
ecPosition3,
normal,
VP, nDotVP, pf,
attenuation);
float spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));
if (spotDot < gl_LightSource[i].spotCosCutoff)
spotAttenuation = 0.0;
else
spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);
attenuation *= spotAttenuation;
ambient = gl_LightSource[i].ambient * attenuation;
diffuse = gl_LightSource[i].diffuse * nDotVP * attenuation;
specular = gl_LightSource[i].specular * pf * attenuation;
}
void PointLight(in int i,
in vec3 eye,
in vec3 ecPosition3,
in vec3 normal,
inout vec4 ambient,
inout vec4 diffuse,
inout vec4 specular)
{
vec3 VP;
float nDotVP, pf, attenuation;
ComputeSpotPointParameters( i,
eye,
ecPosition3,
normal,
VP, nDotVP, pf,
attenuation);
ambient = gl_LightSource[i].ambient * attenuation;
diffuse = gl_LightSource[i].diffuse * nDotVP * attenuation;
specular = gl_LightSource[i].specular * pf * attenuation;
}
const int NumberOfSplits = 1;
uniform bool FirstPass;
bool doShadow;
uniform sampler2DShadow ShadowMap;
uniform float Epsilon;
varying vec4 ShadowCoord[NumberOfSplits];
uniform float SplitDepths[NumberOfSplits];
varying float vertexDepth;
uniform float ShadowAmbientFactor;
uniform bool YieldShadow[NumberOfLights];
bool shadowLookup(vec3 shadowCoord, vec4 diff, float x, float y, out vec4 color)
{
float depth = shadow2D(ShadowMap, shadowCoord).x;
if (depth != 1.0) // in shadow
{
color = vec4(diff * ShadowAmbientFactor);
return false;
}
else // in light
{
color = vec4(diff);
return true;
}
}
uniform bool BackFaceColor;
void main(void)
{
vec4 finalColor;
vec3 normal;
vec4 ambient = vec4(0.0);
vec4 sceneColor, materialAmbient;
vec4 materialSpecular, materialDiffuse;
if (gl_FrontFacing)
normal = normalize(N);
else
normal = -normalize(N); // for backfaces with same color as the front ones
if (gl_FrontFacing || !BackFaceColor) // front face
{
sceneColor = gl_FrontLightModelProduct.sceneColor;
materialAmbient = gl_FrontMaterial.ambient;
materialSpecular = gl_FrontMaterial.specular;
materialDiffuse = gl_FrontMaterial.diffuse;
materialShininess = gl_FrontMaterial.shininess;
}
else // back Face
{
sceneColor = gl_BackLightModelProduct.sceneColor;
materialAmbient = gl_BackMaterial.ambient;
materialSpecular = gl_BackMaterial.specular;
materialDiffuse = gl_BackMaterial.diffuse;
materialShininess = gl_BackMaterial.shininess;
}
if (FirstPass)
finalColor = sceneColor;
else
finalColor = vec4(0,0,0,1);
vec4 DiffuseColor [NumberOfLights];
vec4 SpecularColor[NumberOfLights];
vec4 AmbientColor [NumberOfLights];
vec3 eye = vec3(0.0, 0.0, 1.0);
for (int i=0; i<NumberOfLights; i++)
{
if (LightsEnabled[i])
{
switch(LightsType[i])
{
case 0:
DirectionalLight(i, normal, AmbientColor[i], DiffuseColor[i], SpecularColor[i]);
break;
case 1:
SpotLight(i, eye, ecPosition3, normal, AmbientColor[i], DiffuseColor[i], SpecularColor[i]);
break;
case 2:
PointLight(i, eye, ecPosition3, normal, AmbientColor[i], DiffuseColor[i], SpecularColor[i]);
break;
}
SpecularColor[i] = vec4((SpecularColor[i] * materialSpecular).xyz, 0); // for Pictures with transparent textures, otherwise the Specular Alpha would make them become opaque.
DiffuseColor[i] *= materialDiffuse;
}
}
ambient = vec4(0,0,0,0);
for (int i=0; i < NumberOfLights; i++)
{
// The ambient for the spotlight with shadow is added later after evaluating if it's in shadow
if (LightsEnabled[i] && (LightsType[i] != 1 || !YieldShadow[i]))
ambient += AmbientColor[i];
}
finalColor += ambient * materialAmbient;
// lookup the shadowMaps
vec4 diffuseForShadow;
bool spotLightWithShadow = false;
vec4 spotAmbient;
for (int i=0; i<NumberOfLights; i++)
{
if (LightsEnabled[i])
{
if (YieldShadow[i])
{
diffuseForShadow = DiffuseColor[i];
if (LightsType[i] == 1) // Spot Light
{
spotLightWithShadow = true;
spotAmbient = AmbientColor[i];
}
}
else
finalColor += DiffuseColor[i];
}
}
vec4 coord;
for (int i = 0; i < NumberOfSplits; i++)
{
if (vertexDepth > SplitDepths[i]) // negative values
{
coord = ShadowCoord[0];
break;
}
}
vec3 shadowCoord = vec3(coord / coord.w);
bool inLight = shadowLookup(shadowCoord, diffuseForShadow, 0.0, 0.0, diffuseForShadow);
if (inLight && spotLightWithShadow)
finalColor += spotAmbient * materialAmbient;
finalColor += diffuseForShadow;
for (int i=0; i < NumberOfLights; i++)
{
if (LightsEnabled[i] && YieldShadow[i])
{
if (inLight)
finalColor += SpecularColor[i];
}
else
finalColor += SpecularColor[i];
}
finalColor.w = materialDiffuse.w;
finalColor = clamp (finalColor, 0.0, 1.0);
gl_FragColor = finalColor;
}