I have my object's rotation and translation in a quaternion, which I've converted to a matrix[16].
How do I feed that matrix to OpenGL? I'd-a thought I could just glLoadMatrix() with my new, fancy-pants matrix and all would be good, but I'm getting a blank screen.
(I'm a bit of a GL n00b, so type slowly and use small words ;)
My code looks something like this:
glPushMatrix();
[quaternion makeIdentity]; // reset quat
[quaternion setPitch: rotation.x yaw: rotation.y roll: rotation.z]; // Set up with rotation coords (NOTE: setPitch:yaw:roll: is smart about degrees->radians)
GLdouble matrix[16];
[quaternion matrix: &matrix[0]]; // get quat -> matrix
matrix[12] = location.x; // fill in the translation
matrix[13] = location.y;
matrix[14] = location.z;
glLoadMatrixd(matrix);
glScaled(scale.x, scale.y, scale.z);
// draw geometry here -- snip
glPopMatrix();
I think I'm pretty close but, when I use this code, I get a blank display (everything is glClearColor.)
NOTE: when I skip the quaternion part and do something like this:
glPushMatrix();
glTranslatef(location.x, location.y, location.z);
glRotated(rotation.z, 0, 0, 1.0);
glRotated(rotation.x, 1.0, 0, 0);
glRotated(rotation.y, 0, 1.0, 0);
// draw geometry here -- snip
glPopMatrix();
the display is as expected. The only problem is that my rotations are screwy, due to being applied sequentially. Hence my desire to use quaternions.
If you don't forgot to set current matrix mode to GL_MODELVIEW, your matrix should be loaded correctly. Check your quat -> matrix calculations. I'd start from rotation by zero angle and comparing result with identity matrix.
Quaternions don't have a translation part. The translation must be maintained separately, as is the case in the second code snippet.
I'm not sure the code will do what's desired, anyway. Quaternions won't solve gimbal lock, if the problem is being stated in the very way that introduces gimbal lock in the first place. If the quaternion is being set afresh from pitch/yaw/roll each frame, there will be the same problems as before, and for the same reasons. (And if it appears that's not the case, that's because the quaternion construction code is doing the same thing that the matrix construction code could do, but in this case doesn't: rotating about each rotated axis in turn, rather than rotating about a fixed one.)
To fix this, maintain a quaternion as part of the object's state, and apply each rotation to it directly. This doesn't really buy one much that couldn't be done just as easily with a matrix, though. (I haven't counted the operations, so that's not so say that it may turn out to be rather more efficient one way rather than the other.)
The main advantage of quaternions is that it's easy to interpolate between them, getting something reasonable at each intermediate step, simply by summing the weighted inputs and normalizing the result. SLERP is also an option. The equivalent operation on matrices comes unstuck in certain situations (e.g., with two matrices representing opposing orientations, you'll end up with a column consisting entirely of zeros...), and trying to do something similar with pitch/yaw/roll just generates a big mess.
As for turning one into a matrix, if you've got a quaternion whose vector part is (qx,qy,qz) and whose scalar part is qw, you can turn it into an OpenGL matrix using code like this:
mtx[0]=1.f-2.f*qy*qy-2.f*qz*qz;
mtx[1]=0.f+2.f*qx*qy+2.f*qw*qz;
mtx[2]=0.f+2.f*qx*qz-2.f*qw*qy;
mtx[3]=0.f;
mtx[4]=0.f+2.f*qx*qy-2.f*qw*qz;
mtx[5]=1.f-2.f*qx*qx-2.f*qz*qz;
mtx[6]=0.f+2.f*qy*qz+2.f*qw*qx;
mtx[7]=0.f;
mtx[8]=0.f+2.f*qx*qz+2.f*qw*qy;
mtx[9]=0.f+2.f*qy*qz-2.f*qw*qx;
mtx[10]=1.f-2.f*qx*qx-2.f*qy*qy;
mtx[11]=0.f;
mtx[12]=0.f;
mtx[13]=0.f;
mtx[14]=0.f;
mtx[15]=1.f;
The above was search-and-replace-ed into the above form, so I really hope I didn't screw it up.
Related
I am building a camera class to look arround a scene. At the moment I have 3 cubes just spread arround to have a good impression of what is going on. I have set my scroll button on a mouse to give me translation along z-axis and when I move my mouse left or right I detect this movement and rotate arround y-axis. This is just to see what happens and play arround a bit. So I succeeded in making the camera rotate by rotating the cubes arround the origin but after I rotate by some angle, lets say 90 degrees, and try to translate along z axis to my surprise I find out that my cubes are now going from left to right and not towards me or away from me. So what is going on here? It seems that z axis is rotated also. I guess the same goes for x axis. So it seems that nothing actually moved in regard to the origin, but the whole coordinate system with all the objects was just rotated. Can anyone help me here, what is going on? How coordinate system works in opengl?
You are most likely confusing local and global rotations. Usual cheap remedy is to change(reverse) order of some of your transformation. However doing this blindly is trial&error and can be frustrating. Its better to understand the math first...
Old API OpeGL uses MVP matrix which is:
MVP = Model * View * Projection
Where Model and View are already multiplied together. What you have is most likely the same. Now the problem is that Model is direct matrix, but View is Inverse.
So if you have some transform matrix representing your camera in oder to use it to transform back you need to use its inverse...
MVP = Model * Inverse(Camera) * Projection
Then you can use the same order of transformations for both Model and Camera and also use their geometric properties like basis vectors etc ... then stuff like camera local movements or camera follow are easy. Beware some tutorials use glTranspose instead of real matrix Inverse. That is correct only if the Matrix contains only unit (or equal sized) orthogonal basis vectors without any offset so no scale,skew,offset or projections just rotation and equal scale along all axises !!!
That means when you rotate Model and View in the same way the result is opposite. So in old code there is usual to have something like this:
// view part of matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotate3f(view_c,0,0,1); // ugly euler angles
glRotate3f(view_b,0,1,0); // ugly euler angles
glRotate3f(view_a,1,0,0); // ugly euler angles
glTranslatef(view_pos); // set camera position
// model part of matrix
for (i=0;i<objs;i++)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(obj_pos[i]); // set camera position
glRotate3f(obj_a[i],1,0,0); // ugly euler angles
glRotate3f(obj_b[i],0,1,0); // ugly euler angles
glRotate3f(obj_c[i],0,0,1); // ugly euler angles
//here render obj[i]
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
note the order of transforms is opposite (I just wrote it here in editor so its not tested and can be opposite to native GL notation ... I do not use Euler angles) ... The order must match your convention... To know more about these (including examples) not using useless Euler angles see:
Understanding 4x4 homogenous transform matrices
Here is 4D version of what your 3D camera class should look like (just shrink the matrices to 4x4 and have just 3 rotations instead of 6):
reper4D
pay attention to difference between local lrot_?? and global grot_?? functions. Also note rotations are defined by plane not axis vector as axis vector is just human abstraction that does not really work except 2D and 3D ... planes work from 2D to ND
PS. its a good idea to have the distortions (scale,skew) separated from model and keep transform matrices representing coordinate systems orthonormal. It will ease up a lot of things latter on once you got to do advanced math on them. Resulting in:
MVP = Model * Model_distortion * Inverse(Camera) * Projection
I'm pretty new to openGL, but I have been struggling with why this won't work (not trying to solve a problem necessarily, but just looking to understand the fundamentals)
So basically this draws a grid of triangles that are rotating. What I'm trying to understand is if/how the Push and Pop operations can be removed. When I take them out there is a random scattering. I've tried reversing the rotation after the drawing is complete, switching the translate and rotate commands. I guess the way I see is that I should be able to avoid the push/pop and instead use the rotate each time to increment a few degrees further than the last time, but I'm obviously missing something.
The push/pop matrices are saving/restoring the previous matrix. You can't really avoid doing this, because you would be accumulating translations and rotations.
Remember: glTranslate does not position things. It builds a translation matrix and applies it to the current matrix, whatever that is. So if you do a translate, then rotate, then translate, the last translate will be in the rotated space, not the same space as the rotate.
OpenGL keeps an internal stack of transformation matrices. When you call glPushMatrix() it pushes all the matrices down by one, duplicating the one on the top of the list. This lets you then apply transformations, rotations, scaling etc to your hearts content, and provided you call a glPopMatrix() to remove your newly adjusted transform matrix when you're done, the rest of the 3D world won't change at all.
Note that when I say the rest of the 3D world, that includes your objects the next time your main loop loops. If you don't call glPushMatrix() and then glPopMatrix() you are permanently transforming the world and it will have an (unpredictable) effect on your objects.
So to wrap up, always call glPushMatrix() and glPopMatrix() at the beginning and end of your transformations, unless you know what you're doing and want to have an effect on the rest of the 3D world.
You need to reverse both the translate and rotate commands (in reverse order):
glTranslatef(xF, yF, 0);
glRotatef(angle, 0.0f, 0.0f, 1.0f);
// draw
glRotatef(-angle, 0.0f, 0.0f, 1.0f);
glTranslatef(-xF, -yF, 0);
As #Nicol points out below, it will probably be faster to use glPushMatrix/glPopMatrix, since glRotatef requires building up a rotation matrix with sines and cosines.
What's more, a rotation followed by its inverse rotation may not be exactly the identity due to floating point rounding errors. This means that if you rely on this technique in an inner loop (as you do above), you may accumulate some substantial floating point errors over the course of your entire draw call.
I'm implementing an arcball with openGL (on cpp).
Say, I have an object in the center of the axes system and i want to rotate in several times acording to the original (world) axes.
But, after the first rotation, the axes are changed and all further rotations goes wrong.
Any ideas?
Thanks.
Supply the object with it's own orientation axes (modelview matrix), and then multiply that by the rotation matrices. Check Wikipedia for info on how to construct rotation matrices.
I had to do the same thing myself in an OpenGL ES application, which I describe in a writeup about it here. The original crude approach read the current model view matrix and manipulated it to produce the desired effect:
GLfloat currentModelViewMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
glRotatef(xRotation, currentModelViewMatrix[1], currentModelViewMatrix[5], currentModelViewMatrix[9]);
glGetFloatv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
glRotatef(yRotation, currentModelViewMatrix[0], currentModelViewMatrix[4], currentModelViewMatrix[8]);
This will work, but be aware that the two glGetFloatv() calls will slow your rendering by halting the pipeline. I've since replaced this code with calculations that I perform on my own internal copy of the model view matrix, then I simply write the internally manipulated model view matrix after each rotation. This removes the need to do the expensive matrix read operations.
Add xAngle and yAngle to the current matrix.
Matrix.rotateM(matrix, 0, xAngleADD, matrix[1], matrix[5], matrix[9]);
Matrix.rotateM(matrix, 0, yAngleADD, matrix[0], matrix[4], matrix[8]);
gl.glMultMatrixf(matrix, 0);
I been working on a space sim for sometime now.
At first I was using my own 3d engine with software rasterizer.
But I gave up when the time for implementing textures was due.
Now I started again after sometime and now I'm using Opengl (with SDL) instead to render the 3d models.
But now I hit another brick wall.
I can't figure out how to make proper rotations.
Being a space-simulator I want similar controls to a flighsim
using
glRotatef(angleX, 1.0f, 0.0f, 0.0f);
glRotatef(angleY, 0.0f, 1.0f, 0.0f);
glRotatef(angleZ, 0.0f, 0.0f, 1.0f);
or similar,
does not work properly if I rotate the model(spaceship) first 90 degrees to the left and then rotate it "up".
Instead it rolls.
Here's a image that illustrate my problem.
Image Link
I tried several tricks to try and counter this but somehow I feel I missing something.
It doesn't help either that simulator style rotation examples are almost impossible to find.
So I'm searching for examples, links and the theory of rotating a 3d model (like a spaceship, airplane).
Should I be using 3 vectors (left, up, forward) for orientation as I'm also going to have to calculate things like acceleration from thrusters and stuff that will change with the rotation (orientation?) and from the models perspective points in a direction like rocket-engines.
I'm not very good with math and trying to visualize a solution just give a headache
I'm not sure I entirely understand the situation, but it sounds like you might be describing gimbal lock. You might want to look at using quaternions to represent your rotations.
Getting this right certainly can be challenging. The problem I think you are facing is that you are using the same transformation matrices for rotations regardless of how the 'ship' is already oriented. But you don't want to rotate your ship based on how it would turn when it's facing forward, you want to rotate based on how it's facing now. To do that, you should transform your controlled turn matrices the same way you transform your ship.
For instance, say we've got three matrices, each representing the kinds of turns we want to do.
float theta = 10.0*(pi/180.0)
matrix<float> roll = [[ cos(theta), sin(theta), 0]
[ -sin(theta), cos(theta), 0]
[ 0, 0, 1]
matrix<float> pitch = [[ cos(theta), 0, sin(theta)]
[ 0, 1, 0]
[ -sin(theta), 0, cos(theta)]
matrix<float> yaw = [[1, 0, 0]
[0, cos(theta), sin(theta)]
[0, -sin(theta), cos(theta)]]
matrix<float> orientation = [[1, 0, 0]
[0, 1, 0]
[0, 0, 1]]
each which represent 10 degrees of rotation across each of the three flight attitude axes. Also we have a matrix for your ship's orientation, initially just strait forward. You will transform your ship's vertices by that orientation matrix to display it.
Then to get your orientation after a turn, you need to do just a bit of cleverness, first transform the attitude control matrices into the player's coordinates, and then apply that to the orientation to get a new orientation: something like
function do_roll(float amount):
matrix<float> local_roll = amount * (roll * orientation)
orientation = orientation * local_roll
function do_pitch(float amount):
matrix<float> local_pitch = amount * (pitch * orientation)
orientation = orientation * pitch_roll
function do_yaw(float amount):
matrix<float> local_yaw = amount * (yaw * orientation)
orientation = orientation * local_yaw
so that each time you want to rotate in one way or another, you just call one of those functions.
What you're going to want to use here is quaternions. They eliminate the strange behaviors you are experiencing. Thinking of them as a matrix on steroids with similar functionality. You CAN use matrices better than you are (in your code above) by using whatever OpenGL functionality that allows you to create a rotational matrix upon a particular rotational axis vector, but quaternions will store your rotations for future modification. For example, You start with an identity quaternion and rotate it upon a particular axis vector. The quaternion then gets translated into a world matrix for your object, but you keep the quaternion stored within your object. Next time you need to perform a rotation, then just further modify that quaternion instead of having to try and keep track of X, Y, and Z axis rotation degrees, etc.
My experience is within directx (sorry, no OpenGL experience here), though I did once run into your problem when I was attempting to rotate beachballs that were bouncing around a room & rotating as they encountered floors, walls, and each other.
Google has a bunch of options on "OpenGL Quaternion", but this, in particular, appears to be a good source:
http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation
As you may have guessed by now, Quaternions are great for handling cameras within your environment. Here's a great tutorial:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=Quaternion_Camera_Class
You should study 3D mathematics so that you can gain a deeper understanding of how to control rotations. If you don't know the theory it can be hard to even copy and paste correctly. Specifically texts such as 3D Math Primer(Amazon), and relevant sites like http://gamemath.com will greatly aid you in your project (and all future ones).
I understand you may not like math now, but learning the relevant arithmetic will be the best solution to your issue.
Quaternions may help, but a simpler solution may be to observe a strict order of rotations. It sounds like you're rotating around y, and then rotating around x. You must always rotate x first, then y, then z. Not that there's anything particularly special about that order, just that if you do it that way, rotations tend to work a little bit closer to how you expect them to work.
Edit: to clarify a little bit, you also shouldn't cumulatively rotate across time in the game. Each frame you should start your model out in identity position, and then rotate, x, y, then z, to that frame's new position.
General rotations are difficult. Physicist tend to use some set of so-called Euler angles to describe them. In this method a general rotation is described by three angles taken about three axis in fixed succession. But the three axis are not the X-, Y- and Z- axis of the original frame. They are often the Z-, Y- and Z- axis of the original frame (yes, it really is completely general), or two axis from the original frame followed by an axis in the intermediate frame. Many choices are available, and making sure that you are following the same convention all the way through can be a real hassle.
I'm trying to do a simple rotation in OpenGL but must be missing the point.
I'm not looking for a specific fix so much as a quick explanation or link that explains OpenGL rotation more generally.
At the moment I have code like this:
glPushMatrix();
glRotatef(90.0, 0.0, 1.0, 0.0);
glBegin(GL_TRIANGLES);
glVertex3f( 1.0, 1.0, 0.0 );
glVertex3f( 3.0, 2.0, 0.0 );
glVertex3f( 3.0, 1.0, 0.0 );
glEnd();
glPopMatrix();
But the result is not a triangle rotated 90 degrees.
Edit
Hmm thanks to Mike Haboustak - it appeared my code was calling a SetCamera function that use glOrtho. I'm too new to OpenGL to have any idea of what this meant but disabling this and rotating in the Z-axis produced the desired result.
Ensure that you're modifying the modelview matrix by putting the following before the glRotatef call:
glMatrixMode(GL_MODELVIEW);
Otherwise, you may be modifying either the projection or a texture matrix instead.
Do you get a 1 unit straight line? It seems that 90deg rot. around Y is going to have you looking at the side of a triangle with no depth.
You should try rotating around the Z axis instead and see if you get something that makes more sense.
OpenGL has two matrices related to the display of geometry, the ModelView and the Projection. Both are applied to coordinates before the data becomes visible on the screen. First the ModelView matrix is applied, transforming the data from model space into view space. Then the Projection matrix is applied with transforms the data from view space for "projection" on your 2D monitor.
ModelView is used to position multiple objects to their locations in the "world", Projection is used to position the objects onto the screen.
Your code seems fine, so I assume from reading the documentation you know what the nature of functions like glPushMatrix() is. If rotating around Z still doesn't make sense, verify that you're editing the ModelView matrix by calling glMatrixMode.
The "accepted answer" is not fully correct - rotating around the Z will not help you see this triangle unless you've done some strange things prior to this code. Removing a glOrtho(...) call might have corrected the problem in this case, but you still have a couple of other issues.
Two major problems with the code as written:
Have you positioned the camera previously? In OpenGL, the camera is located at the origin, looking down the Z axis, with positive Y as up. In this case, the triangle is being drawn in the same plane as your eye, but up and to the right. Unless you have a very strange projection matrix, you won't see it. gluLookat() is the easiest command to do this, but any command that moves the current matrix (which should be MODELVIEW) can be made to work.
You are drawing the triangle in a left handed, or clockwise method, whereas the default for OpenGL is a right handed, or counterclockwise coordinate system. This means that, if you are culling backfaces (which you are probably not, but will likely move onto as you get more advanced), you would not see the triangle as expected. To see the problem, put your right hand in front of your face and, imagining it is in the X-Y plane, move your fingers in the order you draw the vertices (1,1) to (3,2) to (3,1). When you do this, your thumb is facing away from your face, meaning you are looking at the back side of the triangle. You need to get into the habit of drawing faces in a right handed method, since that is the common way it is done in OpenGL.
The best thing I can recommend is to use the NeHe tutorials - http://nehe.gamedev.net/. They begin by showing you how to set up OpenGL in several systems, move onto drawing triangles, and continue slowly and surely to more advanced topics. They are very easy to follow.
Regarding Projection matrix, you can find a good source to start with here:
http://msdn.microsoft.com/en-us/library/bb147302(VS.85).aspx
It explains a bit about how to construct one type of projection matrix. Orthographic projection is the very basic/primitive form of such a matrix and basically what is does is taking 2 of the 3 axes coordinates and project them to the screen (you can still flip axes and scale them but there is no warp or perspective effect).
transformation of matrices is most likely one of the most important things when rendering in 3D and basically involves 3 matrix stages:
Transform1 = Object coordinates system to World (for example - object rotation and scale)
Transform2 = World coordinates system to Camera (placing the object in the right place)
Transform3 = Camera coordinates system to Screen space (projecting to screen)
Usually the 3 matrix multiplication result is referred to as the WorldViewProjection matrix (if you ever bump into this term), since it transforms the coordinates from Model space through World, then to Camera and finally to the screen representation.
Have fun