View Full Version : vertex lighting with Cg

12-08-2003, 07:19 AM
I have just started with cg and am trying to write a simple vertex lighting code for four light sources.
It should apply four lights at one pass and lights can be point lights or environment lights (only direction).

However, I can only see my model drawn as black.

Here's my cg code:

struct vpin
float4 position : POSITION;
float4 normal : NORMAL;
float4 color : COLOR0;
float2 texcoord0 : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;

struct vpout
float4 position : POSITION;
float4 color : COLOR0;
float2 texcoord0 : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;

float Illuminate(float4 pos, float radius, float3 ipos, float3 n);

vpout main(vpin IN, uniform float4x4 ModelViewProj,
uniform float4x4 ModelViewIT, uniform float4 LPos[4],
uniform float LRadius[4], uniform float3 LColor[4])

vpout OUT;
float3 normal;
int i;

/* get proper position and normal vectors */
OUT.position = mul(ModelViewProj, IN.position);
normal.xyz = normalize( mul(ModelViewIT, IN.normal).xyz );

/* define diffuse color by light */
OUT.color.a = IN.color.a;
for(i=0; i<4; i++)
OUT.color.rgb += Illuminate(LPos[i], LRadius[i], OUT.position.xyz, normal)*LColor[i].rgb;

OUT.color = clamp(OUT.color, 0.0f, 1.0f);

/* pass texture coordinates */
OUT.texcoord0 = IN.texcoord0;
OUT.texcoord1 = IN.texcoord1;

return OUT;

float Illuminate(float4 pos, float radius, float3 ipos, float3 n)

float3 light;
float diffuse;
float ret;

/* get light vector */
/* ---------------- */
/* 1.0 = pointlight */
/* 0.0 = env. light */
light.xyz = normalize(pos.xyz-(ipos.xyz*pos.w));

/* get diffuse component */
diffuse = dot(light, n);

ret = (diffuse/(light.x*light.x+light.y*light.y+light.z*light.z)) *radius;
ret = diffuse;

return ret;

I know it sucks but I would be grateful if someone could point me out what's wrong.

12-08-2003, 08:01 AM
I'm not really using Cg, but I wouldn't use OUT.position as an input to the Illuminate function.
That aside, optimize the Illuminate function:
(light.x * light.x + light.y * light.y + light.z * light.z) = dot(light, light) = 1.0 for a normalized vector!

12-08-2003, 09:14 AM
Ooops. Forgot that I normalize the light vector. Well I fixed it so that I get the distance from unnormalized light vector.
Then I changed the OUT.position passed to Illuminate() to IN.position (don't know how I messed up with that).

Well it still won't work. I tested with only one single env. light (only dot(l, n), not distance attentuating etc.) and I can see the model lit but it doesn't look right. It looks like there could be something wrong with the normals. However I tried to use opengl fixed pipeline lighting with the same normals and it looked ok. Strange.

12-08-2003, 10:07 PM
Lighting is normally done in world space.
Your IN.position needs to be multiplied by the ModelView matrix for that; normals are correctly multiplied by the inverse transpose.
Unless you're doing modelspace lighting, which is what you did now, when you use IN.position non-transformed, but then you need to transform the lights into modelspace with a a modelview inverse prior to sending the lights to the vertex program.

12-09-2003, 09:08 AM
There's something evil happening, that's for sure. I tried to make just a l.n for vertex colors where n=normal l=(1, 0, 0) (for example). I suppost it should produce a shaded model but it still looked twisted.

12-09-2003, 01:33 PM
Perhaps someone on a cg forum would be able to solve your problem?

12-10-2003, 05:21 AM
After strugling with this for long I decided to check the normals by drawing them and it came out that they actually were screwed up by a diabolical memory overwriting at loading stage. Though it didn't seem to bother opengl fixed lighting.

It works well except for distance attentuating. I use the IN.normal, IN.position and then I multiply the light position with modelview inverse. Still it has no effect if I move the model away to some distance.