Standard lighting with ARB vertex program.

Hi all, I’m trying the following ARB vertex program:


# Performs transformation and ambient, diffuse 
# and specular lighting with a directional light souce

ATTRIB iPos	= vertex.position;
ATTRIB iNormal	= vertex.normal;
ATTRIB iTxCoord = vertex.texcoord;

PARAM mvinv[4]	= { state.matrix.modelview.invtrans };
PARAM mvp[4]	= { state.matrix.mvp };
PARAM lightDir	= state.light[0].position;
PARAM halfDir	= state.light[0].half;
PARAM specExp	= state.material.shininess;
PARAM ambCol 	= state.lightprod[0].ambient;
PARAM diffCol	= state.lightprod[0].diffuse;
PARAM specCol 	= state.lightprod[0].specular;

OUTPUT oPos		= result.position;
OUTPUT oColor	= result.color;
OUTPUT oTxCoord = result.texcoord;

TEMP eyeNormal, temp, dots;

# Transform the vertex to clip coordinates
DP4	oPos.x, mvp[0], iPos;
DP4	oPos.y, mvp[1], iPos;
DP4	oPos.z, mvp[2], iPos;
DP4	oPos.w, mvp[3], iPos;

# Transform the normal into eye space
DP3	eyeNormal.x, mvinv[0], iNormal;
DP3	eyeNormal.y, mvinv[1], iNormal;
DP3	eyeNormal.z, mvinv[2], iNormal;

# Compute diffuse and specular dot products
# and use LIT to compute lighting coefficients
DP3	dots.x, eyeNormal, lightDir;
DP3	dots.y, eyeNormal, halfDir;
MOV	dots.w, specExp.x;
LIT	dots, dots;

# Accumulate color contributions and pass alpha
MAD	temp, dots.y, diffCol, ambCol;
MAD, dots.z, specCol, temp;
MOV	oColor.w, diffCol.w;
MOV	oTxCoord, iTxCoord;


But I can only make it work if light[0] is a directional light, and seems to work only on eye coordinates (as if the light were attached to the view).

Please… where can I find examples of how to perform a standard shading with a point light source in world coordinates? How distance falloff should be treated?

Also, how can I do a COS(x) in a vertex program? :eek:

Some things to remember when doing lighting:

  1. Point lights have position.w = 1, directional lights have position.w = 0.

  2. OpenGL transforms your light position with the current modelview matrix (just like points).

  3. Make sure all the vectors used in lighting are in the same space. (You say you want to perform lighting in world space but your normal transform is view dependent.)

You can approximate cos and many other functions by using the first few terms of the Taylor series expansion.

cos x = 1 - x^2/2! + x^4/4! - x^6/6! + …

You’ll want to range reduce x for best results (closer to 0 the better).


In case you didn’t know, the NVIDIA-specific extension has the SIN and COS instructions built in:

If you’re into that sort of thing.


#define Cos(x) (float)cos(x)

Like that? or;

#include <math.h>

Thanks to all.

I figured out the problem with lighting was that I was using vectors in different CSs.

As for the cos(x) I used Taylor series:

# Constants to aproximate cos() using taylor method
PARAM	cpow 	= { 2, 4, 6, 8 };
PARAM	cden 	= { -0.5, 0.04166667, -0.00138889, 2.48015873e-5 };

MOV		r1.x, one.x;					# Compute cosine of angle.x
POW		r0.x, angle.x, cpow.x;
POW		r0.y, angle.x, cpow.y;
POW		r0.z, angle.x, cpow.z;
POW		r0.w, angle.x, cpow.w;
MUL		r0, r0, cden;
DP4		r1.x, one, r0;

For sin(x) I did cos(x-PI/2) as sin() approximation lacks precission compared to cos() approximation.

Is the above code ok? Any performance suggestion?