vertex lighting with Cg

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.rgb=0.0f;
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.xlight.x+light.ylight.y+light.z*light.z))*radius;
if(pos.w<0.5f)
ret = diffuse;

return ret;
}

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

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!

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.

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.

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.

Perhaps someone on a cg forum would be able to solve your problem?

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.