This shader will give you lighting results exactly like what you would get with non-shader GL_LIGHTS. It will also handle normal maps. You must calculate and pass in the normal map values yourself. I chose to use the texture coord array for texture unit 1 to store the adjusted light X and Y normals, to tell the program which way the light is shining.
I would like to add some specular shininess to the bumpmaps. Can anyone help?
Oh, and I have been using shaders for three days. Before that, I had no idea how they worked, and had never used them at all. 3D Labs’ ShaderGen tool was very helpful.
Vertex program:
vec4 Ambient;
vec4 Diffuse;
uniform int activelights;
uniform int lightmapenabled;
void pointLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3)
{
float nDotVP; // normal . light direction
float nDotHV; // normal . light half vector
float pf; // power factor
float attenuation; // computed attenuation factor
float d; // distance from surface to light source
vec3 VP; // direction from surface to light position
vec3 halfVector; // direction of maximum highlights
// Compute vector from surface to light position
VP = vec3 (gl_LightSource[i].position) - ecPosition3;
// Compute distance between surface and light position
d = length(VP);
// Normalize the vector from surface to light position
VP = normalize(VP);
// Compute attenuation
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);
//}
Ambient += gl_LightSource[i].ambient * attenuation;
Diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation;
//Specular += gl_LightSource[i].specular * pf * attenuation;
}
void spotLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3)
{
float nDotVP; // normal . light direction
float nDotHV; // normal . light half vector
float pf; // power factor
float spotDot; // cosine of angle between spotlight
float spotAttenuation; // spotlight attenuation factor
float attenuation; // computed attenuation factor
float d; // distance from surface to light source
vec3 VP; // direction from surface to light position
vec3 halfVector; // direction of maximum highlights
// Compute vector from surface to light position
VP = vec3 (gl_LightSource[i].position) - ecPosition3;
// Compute distance between surface and light position
d = length(VP);
// Normalize the vector from surface to light position
VP = normalize(VP);
// Compute attenuation
attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * d +
gl_LightSource[i].quadraticAttenuation * d * d);
// See if point on surface is inside cone of illumination
spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));
if (spotDot < gl_LightSource[i].spotCosCutoff)
{
spotAttenuation = 0.0; // light adds no contribution
}
else
{
spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);
}
// Combine the spotlight and distance attenuation.
attenuation *= spotAttenuation;
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);
//
// }
Ambient += gl_LightSource[i].ambient * attenuation;
Diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation;
//Specular += gl_LightSource[i].specular * pf * attenuation;
}
void directionalLight(in int i, in vec3 normal)
{
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, gl_FrontMaterial.shininess);
//}
Ambient += gl_LightSource[i].ambient;
Diffuse += gl_LightSource[i].diffuse * nDotVP;
//Specular += gl_LightSource[i].specular * pf;
}
vec3 fnormal(void)
{
//Compute the normal
vec3 normal = gl_NormalMatrix * gl_Normal;
normal = normalize(normal);
return normal;
}
void ProcessLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3)
{
if (gl_LightSource[i].spotCutoff==180.0)
{
if (gl_LightSource[i].position.w==0.0)
{
directionalLight(i, normal);
}
else
{
pointLight(i, normal, eye, ecPosition3);
}
}
else
{
spotLight(i,normal,eye,ecPosition3);
}
}
void flight(in vec3 normal, in vec4 ecPosition, float alphaFade)
{
vec4 color;
vec3 ecPosition3;
vec3 eye;
int i;
ecPosition3 = (vec3 (ecPosition)) / ecPosition.w;
eye = vec3 (0.0, 0.0, 1.0);
// Clear the light intensity accumulators
Ambient = vec4 (0.0);
Diffuse = vec4 (0.0);
//Calculate active light sources
if (activelights>0)
{
ProcessLight(0,normal,eye,ecPosition3);
if (activelights>1)
{
ProcessLight(1,normal,eye,ecPosition3);
if (activelights>2)
{
ProcessLight(2,normal,eye,ecPosition3);
if (activelights>3)
{
ProcessLight(3,normal,eye,ecPosition3);
}
}
}
}
color=gl_FrontLightModelProduct.sceneColor+Ambient+Diffuse;
color = clamp( color, 0.0, 1.0 );
gl_FrontColor=color;
}
void main (void)
{
vec3 transformedNormal;
float alphaFade = 1.0;
// Eye-coordinate position of vertex, needed in various calculations
vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
// Do fixed functionality vertex transform
gl_Position = ftransform();
transformedNormal = fnormal();
flight(transformedNormal, ecPosition, alphaFade);
//Enable texture coordinates
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_TexCoord[2] = gl_MultiTexCoord2;
gl_TexCoord[3] = gl_MultiTexCoord3;
}
Fragment program:
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform sampler2D texture3;
uniform int lightmapenabled;
uniform float strength;
uniform int bumpmapenabled;
uniform int textureenabled;
void main (void)
{
vec4 color;
//Lighting
//if (lightingenabled==1)
//{
if (lightmapenabled==1)
{
color=texture2D(texture0, gl_TexCoord[0].xy);
}
else
{
color=gl_Color;
}
//}
//Bumpmap
if (bumpmapenabled==1)
{
vec4 bumpmapcolor=texture2D(texture1,gl_TexCoord[2].xy);
color=color*2.0*vec4(strength*((bumpmapcolor.r-0.5)*(gl_TexCoord[1].x-0.5)+(bumpmapcolor.g-0.5)*(gl_TexCoord[1].y-0.5)+(0.5/strength)));
}
//Base Texture
color=color*texture2D(texture2,gl_TexCoord[2].xy)*2.0;
gl_FragColor=clamp(color,0.0,1.0);
}