PDA

View Full Version : shadows problem and gluLookAt()

MaNDROiD
11-28-2004, 01:31 AM
Hi, I'm really baffled by this shadow problem. Here's an outline of the steps I took to implement the planar projection shadows... sorry if it is not well articulated.

1. setup camera using gluLookAt().

2. pushStack
3. perform glRotatef of lights about arbitrary projection plane normal (light keeps spinning).
4. setup Light position using glLightf()
5. get matrix stack using glGetFloatv();
6. multiply light position by this matrix ( variables stored as globals... just used to keep track of where the light is).
6. popStack

7. pushStack.
8. perform transformations on floor object using glRotate..tranlate..scale.
9. get the matrix stack using glGetFloatv();
10. multiply my projection plane points by this matrix (variables stored as globals).
11. draw floor.
12. popStack.

13. pushStack
14. multiply modelview Stack with projection matrix calculated from projection plane points and light point.
15. perform object transformations.
15. popStack

16. perform object transformations.
17. draw object.

ok...now.. the problem i am having is that if I change the gluLookAt() y position the shadow goes off of the plane (sometimes spinning perpendicular to it). But, If I change the gluLookAt() x or z position it is fine. Any help would be great... sadly, I've been trying to figure this out for a while already.

ioquan
11-30-2004, 05:56 AM
You dont need to get the matrix with glGetFloatv and multiply your vertices after you set up the modelview matrix. That is what the modelview matrix is for, so you dont have to perform the multiplication yourself.

So, eliminate steps 3,5,6,8,9,10.

Here is a function to make a matrix that will squish your shadow into the plane based on the light source and the plane equation.

{

float dot = plane.m_coefficients[0] * point.x +
plane.m_coefficients[1] * point.y +
plane.m_coefficients[2] * point.z +
plane.m_coefficients[3];

m_data[0]= dot - plane.m_coefficients[0] * point.x;
m_data[4]= 0 - plane.m_coefficients[1] * point.x;
m_data[8]= 0 - plane.m_coefficients[2] * point.x;
m_data[12]= 0 - plane.m_coefficients[3] * point.x;

m_data[1]= 0 - plane.m_coefficients[0] * point.y;
m_data[5]= dot - plane.m_coefficients[1] * point.y;
m_data[9]= 0 - plane.m_coefficients[2] * point.y;
m_data[13]= 0 - plane.m_coefficients[3] * point.y;

m_data[2]= 0 - plane.m_coefficients[0] * point.z;
m_data[6]= 0 - plane.m_coefficients[1] * point.z;
m_data[10]= dot - plane.m_coefficients[2] * point.z;
m_data[14]= 0 - plane.m_coefficients[3] * point.z;

m_data[3]= 0 - plane.m_coefficients[0];
m_data[7]= 0 - plane.m_coefficients[1];
m_data[11]= 0 - plane.m_coefficients[2];
m_data[15]= dot - plane.m_coefficients[3];

} It's implemented as a class member, where m_data is a 16 element array of floats, but you can do it however you want.

Using this function, your steps 13-15 (note you used #14 twice) should look like this:

13. PopMatrix
14. CreateShadowMatrix using the above function
15. glMultMatrix with the shadow matrix you created
16. Draw object that casts the shadow (will be squished into the plane)
17. PopMatrix

Try that out and let me know if it works.

MaNDROiD
11-30-2004, 03:50 PM
First off thanks for your reply... the reason I used the glGetFloatv() was becase three vertices were given to us and denoted as points of the projection plane. These three points came from an object file which included hundreds of other points that connected to make a table. Now when we try to put this table into the scene, the table gets rotated, scaled and translated. I needed to keep track of the projection plane....hence the multiplication with the Model View Matrix. Same thing goes for the light...the light keeps rotating on top of the table, so I needed to keep track of its location. After calculating the transformed projection plane and light position, I plug those into a similar function for calculating the projection matrix.
Not too sure what to make of it...Am I missing something? Maybe someone can tell me exactly what the gluLookAt call does???

ioquan
12-03-2004, 06:26 AM
I'm not sure exactly what you meant when you were describing your method of finding the plane. In any case, doing this with glGetFloatv on every frame is unneccessary and causes your program to be unneccessarily slow.

One thing is certain, the way you are using the modelview matrix is wrong, and it looks like you are trying to fix it by using glGetFloatv, but you really should fix it by ordering your matrix operations correctly.

First, lets look at how to find the plane equation for your shadow. Then I'll give you some fixed rendering pseudocode which will fix your matrix problems.

If you are just drawing a table that faces upward, the plane equation is

x = 0
y = 1
z = 0
w = however far the y offset is from the origin.
(in the function I gave you these correspond to
plane.coefficents[0] through plane.coefficients[3])

If you are going to be rotating it so it no longer faces upwards, then its a bit trickier. In that case, you should apply any rotations you will be doing to the table to the plane equation as well. Look up math stuff on google to find out how to do this. Do NOT depend on OpenGL's modelview matrix to do all of your transformation math for you. The matrix stacks are there for a very specific purpose, which is NOT to aid you in calculating data that should be calculated PRIOR to your rendering loop. The modelview and projection matrices are there to transform the vertices you send to opengl before they get drawn on the screen and NOTHING else.

In any case, to get this thing working, I suggest you start with a table that always faces upwards and use the plane equation I gave you above. This makes it dead simple to find the actual plane equation that you want. All you have to do is put the table surface's y offset in the w coefficient.

Getting the position of your light should also be dead simple since you should be storing it directly. You should have some struct or class that holds the absolute x,y,z position of your light. Thats all you need. You dont need to get the modelview matrix and transform it or anything goofy like that.

Finally, gluLookAt just modifies the modelview matrix to do a camera transformation. You can do these transformations on your own instead of using gluLookAt (with glTranslate, glRotate, or glMultMatrix). I prefer to calculate the matrix myself and use glMultMatrix. However, for your purposes right now, you should probably stick with gluLookAt to keep things simple.

Hope you're still following...

I will rewrite the steps for you. Take notice, because this is the correct way to do it, and if you fight it, it will only ensure your failure.

The steps assume you have the matrix mode set to modelview and have already set up your projection matrix correctly (with gluPerspective, glOrtho, or glFrustum) at initialization or somehwere else.

During Init
store the plane equation of the plane you want to cast a shadow on. Any time this changes in the future, recalculate the plane equation. For starters, keep your table facing up, and use the simple plane equation I gave you above. Once you have that working you can experiment with rotating the table.

Render Scene:

1. Set the modelview matrix to the identity (glLoadIdentity)
2. gluLookAt(or do your own camera transformation)

3. Call glLightfv with your light's ABSOLUTE coordinates in 3d space. DO NOT USE glTranslate, glRotate, etc., or make any other modifications to the modelview matrix.

4. Push Matrix
5. Do modelview transformations for your table
6. Draw Table
7. Pop Matrix

8. Push Matrix
9. Do modelview transformations for object that will cast shadow
10. Draw Object
11. Pop Matrix

12. Push Matrix
13. Call the function I gave you in my previous post using your plane equation and your light's absolute coordinates
14. glMultMatrix with the matrix returned by #13
15. Do Same transformation as #9
16. set shadow drawing properties (color to gray, depth buffer settings, etc.)
17. Draw object that casts the shadow (it will be squished onto the table surface)
18. Pop Matrix

Repeat steps 8 through 18 for each object that you want to cast a shadow. You can also switch it so 12-18 come before 8-11.

Hope that helps.

Just a final word on this...
You have a problem that a lot of beginning opengl programmers have which is overdependence on the matrix stacks and the high level matrix functions. Symptoms of this include lots of calls to glGetFloatv, glRotate, and gluLookAt, and undesired matrix transformations (such as objects moving when you move the camera).

The problem is that if you dont know how to do the matrix math yourself, when you get to things like shadow casting, collision detection, character/vehicle movement, camera movement, etc. you will be totally lost. Once you realize this, you will want to do the math yourself, so you can keep copies of the matrices around for purposes other than rendering.