PDA

View Full Version : Rendering Objects



Blain
09-11-2009, 10:11 PM
Say I have a spaceship (camera) and another ship I want to render.
How do I render the 2nd ship from the viewpoint of the first ship when I have two positions in space (one for each ship) and two quaternions representing the ships orientations?

Thanks

marshats
09-12-2009, 02:48 AM
This sounds like a case for gluLookAt as follows;



glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, /* camera is at (0,0,5) */
3.0, 1.0, 0.0, /* 2nd ship is at (3,1,0) */
0.0, 1.0, 0.); /* up is in positive Y direction */

/* start drawing your scene */


Of course the numbers will be your global scene cooridinates from your ships actual locations. The "up" vector is the orientation of the camera ... see another openGL post (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Main=50855&Number=2632 34#Post263234) for more explaination

todayman
09-12-2009, 09:21 AM
Also, OpenGL does not use quaternions; it uses matricies. If you're using shaders, you need to figure out the best way to use the quaternions. If you're using the fixed pipeline (or using matricies in your shaders), check out this article (http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation).

Blain
09-12-2009, 05:23 PM
Yeah I should have thought of gluLookAt(). Thanks guys.

Blain
09-12-2009, 09:38 PM
Problem. The camera isn't looking directly at the second ship. Its orientation is determined by another quaternion.

scratt
09-12-2009, 09:44 PM
A while back I was playing with Sean O'Neil's procedural Universe projects.

He has a very nice set of Matrix and Quaternion functions, and an excellent Camera class. You might find his project and source worth a look. :)

marshats
09-13-2009, 11:42 AM
From Maths - AxisAngle to Matrix (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm) I speculate you can get the up vector from the following:



given the spaceship's quaternion
q(theta,(nx,ny,nz))=(cos(theta/2),sin(theta/2)(nx,ny,nz))
with nx^2+ny^2+nz^2=1 condition satisfied

c =cos(theta) // be careful of factor of theta/2 above!
s = sin(theta)
t = 1 - c

[R] =
t*nx*nx + c t*nx*ny - nz*s t*nx*nz + ny*s
t*nx*ny + nz*s t*ny*ny + c t*ny*nz - nx*s
t*nx*nz - ny*s t*ny*nz + nx*s t*nz*nz + c

// so up direction in global cooridinates is determined by a rotation
up = [R]*(0,1,0) ie the middle column of R
= (t*nx*ny - nz*s, t*ny*ny + c, t*ny*nz + nx*s)


So back to your original question -- you want to look out the spaceship along its orientation quaternion n-vector (rather than just at ship 2 like I first thought):



eye = spaceship (camera) location in global cooridinates
center = eye + (nx,ny,nz) // yes vector add eye with n!
up = (t*nx*ny - nz*s,t*ny*ny + c,t*ny*nz + nx*s)
gluLookAt(eyeX,eyeY,eyeZ,
centerX,centerY,centerZ,
upX,upY,upZ)



*** WARNING *** Note, I am just speculating here since I haven't tested this or confirmed with an openGL sim the above. I would expect you to think about this and confirm or deny this :) In other words don't take this as the correct answer just a first pass idea of how you might find the up vector. The eye and center determination I have no doubt about, it is just the determination of the up vector as described in global coordinates that needs confirmation.

Blain
09-13-2009, 05:39 PM
Thanks for the replies. But one last question. Now I have the gluLookAt() working right, how do I actually draw the 2nd ship? The reason its causing problems for me is that glTranslatef() is relative to the "camera", and not to global world coordinates.

Thanks

marshats
09-13-2009, 11:32 PM
If you are using gluLookAt correctly it should be first then you draw your scene ie ship 1 and 2 both given by GLOBAL coordinates.



glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eyeX,eyeY,eyeZ,
centerX,centerY,centerZ,
upX,upY,upZ);

/* start drawing your scene */
glPushMatrix();
glTranslatef(ship one location in global coordinates);
glRotatef(ship ones rotation);
drawShipOne();
glPopMatrix();

glPushMatrix();
glTranslatef(ship two location in global coordinates);
glRotatef(ship two's rotation);
drawShipTwo();
glPopMatrix();


Note the order of operations (Translate,Rotate) is important. If you do (Rotate,Translate) I suspect that may be causing a problem. Or if you are not using push/pop that may also explain your problem.

Can you post the relevant parts of your code ie code near the gluLookAt and the drawing scene code? That may help the readers to debug your problem better.

Blain
09-14-2009, 04:43 PM
glPushMatrix();
glLoadIdentity();
gluLookAt(Pos->x, Pos->y, Pos->z,
In.x, In.y, In.z,
Up.x, Up.y, Up.z);

while (i!=AlienShip.end())
{
glPushMatrix();
glTranslatef(i->Pos.x, i->Pos.y, i->Pos.z);
glMultMatrixf((GLfloat *)m);
i->ShipModel->Draw();
glPopMatrix();
++i;
}

glPopMatrix();

marshats
09-14-2009, 08:17 PM
Your code looks like I would expect-- except the top and bottom Push/Pop pair. Usually the gluLookAt is called at the very beginning of the scene drawing function, only once, immediately after the glMatrixMode(GL_MODELVIEW); glLoadIdentity(); pair. This negates the need to have your outermost push/pop pair. I more expected the code to look like this;



void draw_scene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(Pos->x, Pos->y, Pos->z,
In.x, In.y, In.z,
Up.x, Up.y, Up.z);

while (i!=AlienShip.end())
{
glPushMatrix();
glTranslatef(i->Pos.x, i->Pos.y, i->Pos.z);
glMultMatrixf((GLfloat *)m);
i->ShipModel->Draw();
glPopMatrix();
++i;
}
}


* Is your m matrix purely a rotation? In other words does it have the form (with the last row and column precisely as shown with 0's and 1, and the rij any numerical value)?



m=[r00 r01 r02 0
r10 r11 r12 0
r20 r21 r22 0
0 0 0 1]


* A simple test is to comment out the line "glMultMatrixf((GLfloat *)m);" and see if the ships show up at the "correct" locations ignoring thier rotation orientations which then would be wrong.

* Is your ShipObject::Draw() defined such that the ship's vertices are centered at the origin (0,0,0)?

Blain
09-14-2009, 09:48 PM
the Matrix "m" is purely a rotation, yes, in the form you describe above. The ship shows up in the correct location, but when i move the camera view around, the ship doesn't move around right.
I'm not sure how to describe how it acts without showing a demo.
The ship objects vertices are centered at the origin, yes.
I'll just say this, when I run the program, and rotate the camera left or right, the ship in view rotates appropriately. It's when I pitch the camera it stuffs up.

Thanks.

marshats
09-15-2009, 12:37 AM
Ok, your answers make me think that you are drawing things correctly so we should revisit gluLookAt again. I am proposing a new way to do this.

Suppose your ship with a camera mounted in the cockpit looks like:
http://24.130.61.216/temporary/StarCruiser_Patrick_Fokenthaler.png
This is the ship as drawn in local coordinates (ie no rotations/translations applied) which helps to define the definitions of the camera. Note, the XYZ coordinate definition just right of the ships cockpit.

Based on this particular ship's definition vertices shown in the picture, the camera looking out the cockpit must be defined as:


focus_local = (0,1,0); // camera looks up along along y-axis
up_local = (0,0,1); // the lens is in the XZ-plane, top of camera is at +z and bottom of camera is at -z

//side note, since I don't know how you represent rotations,
//above is true if you represent rotations with a 3x3 matrix.
//
//you will have to add the "w" coordinate = 1 if you
//represent rotations with a 4x4 rotation matrix
focus_local = (0,1,0,w=1); // camera looks up along along y-axis
up_local = (0,0,1,w=1); // the lens is in the XZ-plane, top of camera is at +z and bottom of camera is at -z


* WARNING * If your ship is defined in local coordinates differently then you will have to orient the camera in local coordinates to match or initial drawing.

Now lets move onto drawing the scene: This ship must have an orientation quaternion that you have translated into an openGL rotation matrix, lets call it M_ship. And this same ship is located in global coordinates at


Pos=(Pos->x, Pos->y, Pos->z)


What is is the "In" vector? The camera direction in global cooridinates is the original focus_local rotated by the same rotation as the ship itself; M_ship*focus_local. And the "in" vector is any point starting at the ship's "Pos" along the camera direction "M_ship*focus_local" so


In = Pos+M_ship*focus_local;


What is the " Up" vector in global coordinates required by gluLookAt? This is the camera's "up" direction in local cooridinates rotated by the same rotation as the ship itself.


Up = M_ship*up_local;


So putting it all together you now have what you need to use gluLookAt.



void draw_scene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

In = Pos+M_ship*focus_local; // you need to do explicit Matrix times Vector
Up = M_ship*up_local;

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(Pos->x, Pos->y, Pos->z, // Location in global coordinates of the Ship with camera
In.x, In.y, In.z, // In = Pos+M_ship*focus_local
Up.x, Up.y, Up.z); // Up = M_ship*up_local

while (i!=AlienShip.end())
{
glPushMatrix();
glTranslatef(i->Pos.x, i->Pos.y, i->Pos.z);
glMultMatrixf((GLfloat *)m);
i->ShipModel->Draw();
glPopMatrix();
++i;
}
}



PS The BLENDER drawing is something I downloaded off the web. The author requests credit be given whenever shown publicly. So here it is
///////////////////////////////////////////////////////////
"Have Fun with This StarCruiser.

You can use it like you want to, but if you public a file, which
inkluding this Stare-Cruiser, I want you to tell my Name.

greeds
Patrick Fokenthaler (DonFokn)

Contact:
ICQ: 257682533"

marshats
09-15-2009, 09:29 AM
I had a little time to think, and realized that I hadn't drawn the ship with the camera. You need to draw it after use of gluLookAt.

Nor did I account for the fact that the camera is not at the origin of the figure shown above. In local coordinates of the ship, the camera is at



camera_pos_local = (0,0.25,.75) // of course this depends
// on the particular ship
// geometry, you will have
// different numbers

The effect of this camera offset is expressed in "In" and a new "Eye" Position used in gluLookAt. The code would be generalized as follows;



void draw_scene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

Eye = Pos+M_ship*( camera_pos_local);
In = Pos+M_ship*(focus_local+camera_pos_local);
Up = M_ship*up_local;

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( Eyex, Eyey, Eyez,
In.x, In.y, In.z,
Up.x, Up.y, Up.z);

while (i!=AlienShip.end())
{
glPushMatrix();
glTranslatef(i->Pos.x, i->Pos.y, i->Pos.z);
glMultMatrixf((GLfloat *)m);
i->ShipModel->Draw();
glPopMatrix();
++i;
}

//draw ship with camera
glPushMatrix();
glTranslatef(Pos->x, Pos->y, Pos->z);
glMultMatrixf((GLfloat *)M_ship);
Ship_having_camera->Draw();
glPopMatrix();
}

Blain
09-16-2009, 10:58 PM
Thanks for help you've given here. I'll eventually get this thing working.

Thanks again.

marshats
09-17-2009, 12:14 AM
I have learned a lot form people on openGL forums so I try to help when I can :)

When you do verify or find a solution it may help others if you post it here. I am sure lots of people are working on similar quaternion problems and could benefit from your efforts.

Anyhow, if I get a chance to expand my code suggested above and it works I will post it here ... stay tuned.