Jump to content
  • Advertisement
Sign in to follow this  
metalcrusader

Angle between Light and Normal II

This topic is 4628 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

HELLo again! I still want to calculate the angle between a normal and a lightsource. My first approach was to transform the normal in the space of the lightvector - the Eyespace. But this approach seems to be camera-depending. Because of that i let the normal as it is but transform the lightvector to the objectspace. For doing that, i needed to inverse the modelviewmatrix. In another Forum i found some code, which does that. Here it is:
void Matrix_4x4_Inverse(float Matrix_in_rhs[16], float Matrix_out_rhs[16])
{
	// Rotation
	Matrix_out_rhs[ 0] = Matrix_in_rhs[ 0]; Matrix_out_rhs[ 1] = Matrix_in_rhs[ 4]; Matrix_out_rhs[ 2] = Matrix_in_rhs[ 8];
	Matrix_out_rhs[ 4] = Matrix_in_rhs[ 1]; Matrix_out_rhs[ 5] = Matrix_in_rhs[ 5]; Matrix_out_rhs[ 6] = Matrix_in_rhs[ 9];
	Matrix_out_rhs[ 8] = Matrix_in_rhs[ 2]; Matrix_out_rhs[ 9] = Matrix_in_rhs[ 6]; Matrix_out_rhs[10] = Matrix_in_rhs[10];	
	Matrix_out_rhs[ 3] = 0.0f;
	Matrix_out_rhs[ 7] = 0.0f;
	Matrix_out_rhs[11] = 0.0f;
	Matrix_out_rhs[15] = 1.0f;	
	// Translation (Translation is minus the dot of Tranlation and Rotations)
	Matrix_out_rhs[12] = -(Matrix_in_rhs[12] * Matrix_in_rhs[ 0]) - (Matrix_in_rhs[13] * Matrix_in_rhs[ 1]) - (Matrix_in_rhs[14] * Matrix_in_rhs[ 2]);
	Matrix_out_rhs[13] = -(Matrix_in_rhs[12] * Matrix_in_rhs[ 4]) - (Matrix_in_rhs[13] * Matrix_in_rhs[ 5]) - (Matrix_in_rhs[14] * Matrix_in_rhs[ 6]);
	Matrix_out_rhs[14] = -(Matrix_in_rhs[12] * Matrix_in_rhs[ 8]) - (Matrix_in_rhs[13] * Matrix_in_rhs[ 9]) - (Matrix_in_rhs[14] * Matrix_in_rhs[10]);
}

After invering the modelviewmatrix i multiply it with my lightvector to get it in objectspace. Now I can calculate the dot-product between them - but again it is camera-depending!!!??? Does anyone know why??? Here comes the rest of my code:
bool flaeche4::isBackface( )
{
	GLdouble MVmatrix[16];
	glGetDoublev( GL_MODELVIEW_MATRIX, MVmatrix);
	
	float mvMatrix[16];
	for (int i = 0; i < 16; i++)
	{
		mvMatrix = (float)MVmatrix;
	}
	
	float invMvMatrix[16];
	Matrix_4x4_Inverse( mvMatrix, invMvMatrix);

	GLfloat lightPos[4];	
	glGetLightfv(GL_LIGHT1, GL_POSITION, lightPos);	
	Vektor4 light; light.x = lightPos[0]; light.y = lightPos[1]; light.z = lightPos[2]; light.w = lightPos[3]; 
	
	Vektor4 norm = this->berechneNormale();
	
	Vektor4 objSplight; // in Objectspace transformed light
	objSplight.x = light.x * invMvMatrix[0]  + light.y * invMvMatrix[4]  + light.z * invMvMatrix[8]  + light.w * invMvMatrix[12];
	objSplight.y = light.x * invMvMatrix[1]  + light.y * invMvMatrix[5]  + light.z * invMvMatrix[9]  + light.w * invMvMatrix[13];
	objSplight.z = light.x * invMvMatrix[2]  + light.y * invMvMatrix[6]  + light.z * invMvMatrix[10] + light.w * invMvMatrix[14];
	objSplight.w = light.x * invMvMatrix[3]  + light.y * invMvMatrix[7]  + light.z * invMvMatrix[11] + light.w * invMvMatrix[15];
	
	Vektor4 center = (this->a).plusVec( this->c); // get the Center of the surface
	center.x = center.x / center.w; center.y = center.y / center.w; center.z = center.z / center.w; center.w = center.w / center.w;
	Vektor4 diff = objSplight.minusVec( center);
	
	float lightLang = sqrt( objSplight.x * objSplight.x + objSplight.y * objSplight.y + objSplight.z * objSplight.z); 
	float diffLang = sqrt( diff.x * diff.x + diff.y * diff.y + diff.z * diff.z );
	
	double top = norm.x * diff.x + norm.y * diff.y + norm.z * diff.z;
	
	double bottom = lightLang * diffLang;
	
	double dotProdukt = top / bottom;
	
	if ( dotProdukt >= 0) 
	{ 
		return false;
	}
	else return true;
}


Share this post


Link to post
Share on other sites
Advertisement
If you want to convert a vector or normal from one object in the scene to another object within the scene, the modelview matrix is not what you want to use. The modelview matrix converts a vector from object space to camera space (hence your camera dependancy). To convert a vector v from the coordinate system of an object A to the coordinate system of an object B you'll need to do the following:
- Convert v to world space:
v_world = A.model_matrix * v
- convert v_world to the coodrinate system of B:
v_in_B = B.model_matrix.inverse() * v_world

if v is already in world coordinates, step one can be skipped.

Now the real problem: in OpenGL they made the (IMO unfortunate) decision to combine model and view matrix into one. This means that there is no way to obtain a pure model matrix with glGetFloatv(...). Fortunately, you can convert to view space as well:
- Convert v to view space:
v_view = A.modelview_matrix * v
- convert v_view to the coodrinate system of B:
v_in_B = B.modelview_matrix.inverse() * v_view

if v is already in world coordinates, step one can *not* be skipped, otherwise the view transform would not be cancelled out and you get camera dependant behavior again. Use the view matrix instead of the modelview matrix of A.

Tom

[Edited by - dimebolt on October 21, 2005 5:48:04 AM]

Share this post


Link to post
Share on other sites
What means this->a and this->c of the plane class?

If I see it correct, the objSplight is a position (point) and not a direction vector?! If so, your dot prouct isn't correct.

(Besides the above, you may return a boolean value directly, as in
return dotProdukt<0;
instead of translating the one boolean to another.)

@dimebolt: I agree it would be better to do these computations in model space, but I remember that it was a need to do it in eye space. However, as long as only one camera is in action, also computations in the camera co-ordinate frame can be seen as camera independent, since the camera is "canceled out" (being in view standard co-ordinates).

Share this post


Link to post
Share on other sites
Quote:
Original post by haegarr
@dimebolt: I agree it would be better to do these computations in model space, but I remember that it was a need to do it in eye space. However, as long as only one camera is in action, also computations in the camera co-ordinate frame can be seen as camera independent, since the camera is "canceled out" (being in view standard co-ordinates).

Agreed, maybe you read my post before I edited it? My second solution uses the modelview twice, which cancels out the view matrix. I edited it a bit more to match your point :)

Tom

Share this post


Link to post
Share on other sites
@dimebolt: so much agreements :-) hopefully, also metalcrusader does agree ...

Ups, aren't the matrices of OpenGL in column major order? That is
0 4 8 12
1 5 9 13
2 6 10 14
3 7 11 15
right? If so, the computation of objSplight as the transformation of light is also not correct.

Share this post


Link to post
Share on other sites
Thanks!
@haegarr:
1. I fixed my light-transformation so it considers the column major order.
2. this->a is one point of my plane( flaeche) and this->c is the point that lies diagonally to a.

@dimebolt: you said:
Fortunately, you can convert to view space as well:
- Convert v to view space:
v_view = A.modelview_matrix * v
- convert v_view to the coodrinate system of B:
v_in_B = B.modelview_matrix.inverse() * v_view

I think i´ve done exactly that! v_view is my lightvector. It is defined in viewspace (or not?). So i have to multiply it by the inverse of the modelviewmatrix of B ( my plane).
My problem is, that i define my objects directly in the world coordinates. So not every plane´s origin is 0/0/0/1. I use that coordinates to calculate the normal. Do i have a modelview-matrix for my plane anyway? And how do i get it?

Share this post


Link to post
Share on other sites
@metalcrusader

I still believe that you compute the product not correctly from the plane's normal and the direction to the light. I expect something like this:
cos<norm,diff> := norm dot diff / ( |norm| * |diff| )
but I see something like this:
cos<norm,diff> := norm dot diff / ( |objSplight| * |diff| )

Another little optimization: Normalizing center by 4 divisions isn't that fast. Since you've added two points, the center.w has to be 2, and hence it would be more efficient to multiply center.x, center.y, and center.z by 0.5f, and to set center.w to 1.

Share this post


Link to post
Share on other sites
Quote:
Original post by metalcrusader
I think i´ve done exactly that! v_view is my lightvector. It is defined in viewspace (or not?).

I cannot judge that without your rendering code, but most likely it's not.
Assuming your code conceptually looks something like this:

SetupProjectionMatrix();
SetupViewMatrix();
SetupLight(); // contains a glLightfv(light, GL_POSITION, ...) call
for object in all_objects:
glPushMatrix();
MatrixMult(object.model_matrix); // contains call to glMultMatrix or glTranslate/glRotate/glScale
DrawObject(object);
glPopMatrix()

In this case the light is in world coordinates and you will need to transform it.
If the light was defined in view space, SetupLight() would appear before SetupViewMatrix() and will move with the camera. If that's what you do, the outcome is supposed to be dependant on the camera (as the light is 'attached' to it).

I'll augment the above pseudo code with code to get the light position in object space:

SetupProjectionMatrix();
SetupViewMatrix();

// get current mv matrix:
light_mv_matrix = GetModelView();

SetupLight();
for object in all_objects:
glPushMatrix();
MatrixMult(object.model_matrix);

// get obj mv:
obj_mv_matrix = GetModelView();
// multiply light_position with light_mv, and then with obj_mv
light_in_obj = obj_mv_matrix.inverse() * light_mv_matrix * light_position;

DrawObject(object);
glPopMatrix()



I would really advice you to write some more standard vector4 and matrix4x4 functions to do stuff like getting the length of a vector, dot product etc. That would really improve readability.

Tom

EDIT: and I agree with haegarr once more, that the angle between v1 and v2 should be something like: angle = acos(dot(v1, v2) / (v1.length() * v2.length()));

Share this post


Link to post
Share on other sites
Quote:
Original post by dimebolt
I would really advice you to write some more standard vector4 and matrix4x4 functions to do stuff like getting the length of a vector, dot product etc. That would really improve readability.


Yeah, not only that, it also avoids careless mistakes since it prevents to write down such (more or less) complex stuff over and over again.

Share this post


Link to post
Share on other sites
@ haegarr:
i fixed the dot - product and use your optimization.
@dimebolt:
i set up the light before defining any matrices: Here is an extract of my main:

...
glutCreateWindow (argv[0]);
init ();
glutReshapeFunc (reshape);
glutDisplayFunc(display);
glutMainLoop();



my init():

...
glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST);
GLfloat lmodel_ambient[] = { 1.0, 1.0, 1.0, 1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

glLightfv( GL_LIGHT1, GL_POSITION, lightPosition1);
glLightfv( GL_LIGHT1, GL_AMBIENT, ambientLight1);
glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuseLight1);
glLightfv( GL_LIGHT1, GL_SPECULAR, diffuseLight1);

glEnable (GL_LIGHTING);
glEnable (GL_LIGHT1);
glEnable(GL_COLOR_MATERIAL);



my reshape()

glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60, 1, 1, 20);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();



and in the display function there are the viewing transformations:

glLoadIdentity();
gluLookAt( xPos, hoch, zPos, xPos, hoch, zPos-1, 0.0, 1.0, 0.0);
glRotatef(spin, 0.0, 1.0, 0.0); // so i can rotate the camera.
glPushMatrix();


... so my light should be camera-independent. But sadly it isn´t. It moves as i rotate the camera...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!