Well I had to change some things to the shader for testing. I am on a First generation Mac Book Pro with an ATI Radeon x1600. I put all the lighting functions into on fragment shader and had to make some changes to the order because otherwise I had some errors telling me that the functions were not found. Another thing is that I replaced all the gl_LightSource[i]…; with gl_LightSource[0]…; because otherwise it didn’t work. For some reason the is were only accepted if I changed them to const int but that didn’t work for passing them from function to function. so my final fragment shader code looks like this:
varying vec3 normal;
varying vec3 vertex;
const vec4 AMBIENT_BLACK = vec4(0.0, 0.0, 0.0, 1.0);
const vec4 DEFAULT_BLACK = vec4(0.0, 0.0, 0.0, 0.0);
bool isLightEnabled(in int i)
{
// A separate variable is used to get
// rid of a linker error.
bool enabled = true;
// If all the colors of the Light are set
// to BLACK then we know we don't need to bother
// doing a lighting calculation on it.
if ((gl_LightSource[i].ambient == AMBIENT_BLACK) &&
(gl_LightSource[i].diffuse == DEFAULT_BLACK) &&
(gl_LightSource[i].specular == DEFAULT_BLACK))
enabled = false;
return(enabled);
}
float calculateAttenuation(in int i, in float dist)
{
return(1.0 / (gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist));
}
void directionalLight(in int i, in vec3 N, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
const int b = 0;
vec3 L = normalize(gl_LightSource[b].position.xyz);
float nDotL = dot(N, L);
if (nDotL > 0.0)
{
vec3 H = gl_LightSource[b].halfVector.xyz;
float pf = pow(max(dot(N,H), 0.0), shininess);
diffuse += gl_LightSource[b].diffuse * nDotL;
specular += gl_LightSource[b].specular * pf;
}
ambient += gl_LightSource[b].ambient;
}
void pointLight(in int i, in vec3 N, in vec3 V, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
vec3 D = gl_LightSource[0].position.xyz - V;
vec3 L = normalize(D);
float dist = length(D);
float attenuation = calculateAttenuation(0, dist);
float nDotL = dot(N,L);
if (nDotL > 0.0)
{
vec3 E = normalize(-V);
vec3 R = reflect(-L, N);
float pf = pow(max(dot(R,E), 0.0), shininess);
diffuse += gl_LightSource[0].diffuse * attenuation * nDotL;
specular += gl_LightSource[0].specular * attenuation * pf;
}
ambient += gl_LightSource[0].ambient * attenuation;
}
void spotLight(in int i, in vec3 N, in vec3 V, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
vec3 D = gl_LightSource[0].position.xyz - V;
vec3 L = normalize(D);
float dist = length(D);
float attenuation = calculateAttenuation(0, dist);
float nDotL = dot(N,L);
if (nDotL > 0.0)
{
float spotEffect = dot(normalize(gl_LightSource[0].spotDirection), -L);
if (spotEffect > gl_LightSource[0].spotCosCutoff)
{
attenuation *= pow(spotEffect, gl_LightSource[0].spotExponent);
vec3 E = normalize(-V);
vec3 R = reflect(-L, N);
float pf = pow(max(dot(R,E), 0.0), shininess);
diffuse += gl_LightSource[0].diffuse * attenuation * nDotL;
specular += gl_LightSource[0].specular * attenuation * pf;
}
}
ambient += gl_LightSource[0].ambient * attenuation;
}
void calculateLighting(in int numLights, in vec3 N, in vec3 V, in float shininess,
inout vec4 ambient, inout vec4 diffuse, inout vec4 specular)
{
// Just loop through each light, and if its enabled add
// its contributions to the color of the pixel.
for (int i = 0; i < numLights; i++)
{
if (isLightEnabled(i))
{
if (gl_LightSource[0].position.w == 0.0)
directionalLight(i, N, shininess, ambient, diffuse, specular);
else if (gl_LightSource[0].spotCutoff == 180.0)
pointLight(i, N, V, shininess, ambient, diffuse, specular);
else
spotLight(i, N, V, shininess, ambient, diffuse, specular);
}
}
}
vec3 findDiffuse(in vec3 n, in vec3 lVec, in vec3 lCol){
vec3 ccol = vec3(0.0);
float diffuse = max(dot(n, lVec), 0.0);
if(diffuse < 0.125)
diffuse = 0.125;
ccol = lCol * diffuse;
return (ccol);
}
void main()
{
// Normalize the normal. A varying variable CANNOT
// be modified by a fragment shader. So a new variable
// needs to be created.
vec3 n = normalize(normal);
vec4 ambient, diffuse, specular, color;
// Initialize the contributions.
ambient = vec4(0.0);
diffuse = vec4(0.0);
specular = vec4(0.0);
// In this case the built in uniform gl_MaxLights is used
// to denote the number of lights. A better option may be passing
// in the number of lights as a uniform or replacing the current
// value with a smaller value.
calculateLighting(1, n, vertex, gl_FrontMaterial.shininess,
ambient, diffuse, specular);
color = gl_FrontLightModelProduct.sceneColor +
(ambient * gl_FrontMaterial.ambient) +
(diffuse * gl_FrontMaterial.diffuse) +
(specular * gl_FrontMaterial.specular);
// Re-initialize the contributions for the back
// pass over the lights
ambient = vec4(0.0);
diffuse = vec4(0.0);
specular = vec4(0.0);
// Now caculate the back contribution. All that needs to be
// done is to flip the normal.
calculateLighting(1, -n, vertex, gl_BackMaterial.shininess,
ambient, diffuse, specular);
color += gl_BackLightModelProduct.sceneColor +
(ambient * gl_BackMaterial.ambient) +
(diffuse * gl_BackMaterial.diffuse) +
(specular * gl_BackMaterial.specular);
color = clamp(color, 0.0, 1.0);
gl_FragColor = color;
}
vertex shader:
varying vec3 normal;
varying vec3 vertex;
void main(void)
{
normal = normalize(gl_NormalMatrix * gl_Normal);
vertex = vec3(gl_ModelViewMatrix * gl_Vertex);
gl_Position = ftransform();
}
ATI drivers suck. as I said I can only access the lightsources using a const int. But since the test only uses light0 the above example should work correctly without showing the errors from the first image.
Thanks!