Shader for standard gl lighting, plus normal maps

BlitzMax Forums/OpenGL Module/Shader for standard gl lighting, plus normal maps

JoshK(Posted 2006) [#1]
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;

}[/CODE]Fragment program:
[CODE]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);
}