Advertisement

Cg Per Pixel Lighting - wrong lighting

Started by November 04, 2004 08:46 AM
20 comments, last by RipTorn 19 years, 11 months ago
Hello, I have a problem with PPL - when I change my camera position (I use gluLookAt), lighting gets wrong. Download this and use N/M, U/I or J/K to move the camera and to see what I mean. Any ideas what am I doing wrong? I'm doing lighting in eye-space. Shaders:

//
// Vertex Program
//


void vp_main (uniform float4x4		  modelviewprojmatrix,
			  uniform float4x4		  modelviewmatrix,
			  uniform float4x4		  inv_transpose,
			  float4 pos			: POSITION,
			  float3 normal			: NORMAL,


			  out float3 out_norm	: TEXCOORD0,
			  out float3 out_vpos	: TEXCOORD1,
			  out float4 out_pos	: POSITION)
{
	out_pos		= mul (modelviewprojmatrix, pos);			// Object Space to Clip Space
	out_vpos	= mul (modelviewmatrix, pos).xyz;			// Object Space to Eye Space
	out_norm	= mul ((float3x3) inv_transpose, normal);	// Object Space to Eye Space
}


//
// Fragment Program
//


void fp_main (uniform float3 material,
			  uniform float3 light_ambient,
			  uniform float3 light_diffuse,
			  uniform float3 light_specular,
			  uniform float	 shine,
			  
			  uniform float3 light_pos,
			  uniform float3 eye_pos,

			  float3 normal			: TEXCOORD0,
			  float3 vertex_pos		: TEXCOORD1,
			  
			  out float4 out_color : COLOR)
{	
	// Ambient Component
	float3 ambient_l = material * light_ambient;
	
	// Diffuse Component
	float3 N = normalize (normal);
	float3 L = normalize (light_pos - vertex_pos);

	float3 diffuse_l = material * light_diffuse * max (dot (N, L), 0.0);

	
	// Specular Component
	float3 V = normalize (eye_pos - vertex_pos);
	float3 H = normalize (V + L);		

	float3 specular_l = material * light_specular * pow ( max (dot (N, H), 0.0), shine);
	if (dot (N, L) <= 0.0) { specular_l = 0.0; }
	

	out_color.rgb = ambient_l + diffuse_l + specular_l;
	out_color.a		= 1.0;
}





Render function:

	gluLookAt (cp[0], cp[1], cp[2], cl[0], cl[1], cl[2], 0, 1, 0);

        // Update light/eye position
	cgGLSetParameter3fv (light_pos, l_p);
	cgGLSetParameter3fv (eye_pos,   cp);

		
	// Enable Shaders
	cgGLEnableProfile (cgProfileVertex);	cgGLBindProgram (cgProgramVertex);
	cgGLEnableProfile (cgProfileFragment);	cgGLBindProgram (cgProgramFragment);

	RenderSurface (...);




I pass matrices in RenderSurface() after all transformations:

	cgGLSetStateMatrixParameter (modelviewprojmatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
		cgGLSetStateMatrixParameter (modelviewmatrix, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);
		cgGLSetStateMatrixParameter (invtranspose, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);





I don't understand why you are using the inverse transpose modelview matrix to rotate your normals...

I would expect this is what you want:
out_norm	= mul (modelviewmatrix, float4(normal,0)).xyz;


That will rotate by the modelview matrix, but it won't translate due to the zero w-coord.

See if it makes a difference...

[smile]

Advertisement
No, it's the same. :( That's really weird.
Thanks anyway.
Try to use:

float4 modelviewprojmatrix = glstate.matrix.mvp;
float4 modelviewmatrix = glstate.matrix.modelview[0];
float4 inv_transpose = glstate.matrix.invtrans.modelview[0];

and see what happens. You usually don't have to send the matrices by using parameters.
Still the same. Looks like problem is somewhere else, not in the shader.
Hi :)

First) To rotate your normals into eye-space, you should just multiply with the modelview-matrix (as ZMaster proposed, use glstate.matrix.modelview[0], although this is not supported on all profiles).

Now that your normals are in eye-space, you also need to rotate your light-position and direction into eye-space. For specular-intensity calculations you ofcourse also need to rotate your eye-position into eyespace.

To do this:

Send your lightposition to your vertex-shader. Calculate the direction in object-space (in your case: light_pos - pos.xyz), normalize it and send it to the fragment-shader.
Same goes for the eyedir-vector.

If you have any questions, please mail me at: hempel@post.cybercity.dk

Best regards,
Roquqkie
Advertisement
well I see your having issues still,

well, I downloaded your example program this time, and honestly, it looks correct to me. The lighting looks fine. Specular is good, diffuse is good. ambient is good. it's all good.


BTW:

I would strongly suggest you do not use 'if' statements, or anything else that branches. In either a vertex shader, and especially not in a pixel shader. In the case of the pixel shader, simply using the 'min' built in function would do the job. Although pow() should never return a negative number anyway, so it's not needed.
saturate effectivly does both min and max (clamps to 0-1) and is effetivly 'free', where as min/max can take a few cycles. You might also want to look into the 'lit' Cg command. lit is especially fast on radeons (single cycle I believe).

Also there is a message box with "CG error: no error has occured" - I had this myself once I believe :)
Well everyone who has tried to even read that code gets rating++ (obviously all of you who posted here).

Roquqkie: didn't work, thanks for offering help anyway.

RipTorn: Hmm, correct? Well that is something I wouldn't expect, really. :) I've always thought specular highlight should just change its intensity when I move the camera, not the entire position. That is probably due to the fact I was using a plane. I've just tried these shaders on a teapot and lighting looks just fine there.
Thanks for the tip on branching&stuff as well.
You get the highest rating for all this.
About that Cg Error Msgbox, yeah, it will always pop up, even if there is no error. I will remove that at the end anyway.


However, if anyone would like to use those shaders with camera-independent light (specular won't change), just PM or email me.
Hi WingMan: Please post your code after you'd made my modifications... It's supposed to work! ;)

Best regards,
Roquqkie
Specular is the direct reflection of light, so if the plane was a mirror, the centre of the specular spot would be where the light source would be reflected. In this way, the code looks correct :)

the diffuse also looks correct as if you move the light source a good distance away, the plane fades to grey, which I guess is your ambient colour.


Now the real challenge begins however :) - using tangent spaces to support surfaces that arn't flat along one axis. such as in this thread.

This topic is closed to new replies.

Advertisement