Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

  1. #1
    Member Regular Contributor
    Join Date
    Sep 2002
    Posts
    365

    Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

    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:
    Code :
    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:
    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);
    }

  2. #2

    Re: Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

    Have you checked if this really works:
    Code :
    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);
    				}
    			}
    		}
    	}
    I mean, do the if-statements really do what they should? I just implementen something like that and also tried many variations but no matter what, the performance is the same, no matter if I use 1 light or 8 lights on a Geforce 7800GS. Seems like you could just skip the ifs and set the lightcolor to zero, that would even perform faster.

    Case

  3. #3
    Super Moderator OpenGL Lord
    Join Date
    Dec 2003
    Location
    Grenoble - France
    Posts
    5,575

    Re: Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

    I think a loop would be better (at least, it looks simpler to optimize, given that activelights is a uniform) :
    Code :
    for (i =0; i< activelights;i++) {
       ProcessLight(i,normal,eye,ecPosition3);
    }

  4. #4

    Re: Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

    Yes, a loop would be nice - but a loop doesn´t work in fragment programs, at least not on Geforce 7 Hardware.

  5. #5

    Re: Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

    Just found the way to make the if-construction actually do something on nvidia-Hardware: you need to provide
    #pragma optionNV(ifcvt none)

  6. #6
    Member Regular Contributor
    Join Date
    Sep 2002
    Posts
    365

    Re: Shader for default GL_LIGHTING behavior, with multiple lights, plus normal mapping

    I ended up changing all those nested if statements to individual ones, like this:
    Code :
    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);
    }
    The shader was causing crashes on ATI cards with no explanation. I changed the if statements structure and it worked fine. This begs the question whether GLSL can be considered a programming language at all, since it freaks out if you do anything other than simple conditionals.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •