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.
Related
When I was running this code I got 2 spheres that are scaled and the transformation of the first sphere also affected the second sphere.
glTranslatef(0,1,0);
glScalef(1,1,0.5);
glutWireSphere(0.5, 20, 16);
glTranslatef(0,-1,0);
glutWireSphere(0.5, 20, 16);
I have 3 questions:
glTranslate and glScale considered to be one or two matrices when I use the pop/push matrix?
how did the transformation of the first sphere affect the second sphere?
how can I save only the scaling transformation with the glPushMatrix so that the glTranslatef(0,1,0) won't affect the second sphere ?
First, you should know that you're using deprecated functionality. You should look up how to do the above with shaders.
That said, to answer your questions:
There is a current transform matrix. Any matrix operations you perform are concatenated onto the current transform matrix (except glLoadMatrix() which overwrites it). So scales, translates, multiplies, etc. all change the current matrix. When you draw some geometry using glBegin() and glEnd(), they use the current transform matrix. (Much of OpenGL works this way. There's a bunch of state and whatever the current state is, that's what's used to draw stuff.)
Since the transformations are concatenated, the first is drawn with just the translate and scale. The second is drawn with the translate and scale plus another translate. The second translate happens after a scale, so it's units are different than the first translate's units.
I'm not sure I understand what you're trying to achieve with pushing and popping the matrices. Normally, you'd use glPushMatrix()/glPopMatrix() like this:
glPushMatrix();
glTranslatef(0,1,0);
glScalef(1,1,0.5);
glutWireSphere(0.5, 20, 16);
glPopMatrix();
glutWireSphere(0.5, 20, 16);
But did you want both to be scaled, but only 1 to be translated instead? If you clarify, I can fix the above to do what you intend.
Basically, glPushMatrix() saves the current state of the matrix. You then make any changes to it that you want to, and draw any geometry with those changes. Then when you call glPopMatrix() it restores it to the state it was in when you called glPushMatrix().
I don't know the right term to describe it that is why I can't find it in Google. All I want is to scale the object, specifically, 2D rectangle but keep it on its XY coordinates.
My current solution is this:
glTranslatef(x, y, 0);
glScalef(scaleX, scaleY, 0);
glTranslatef(-x, -y, 0);
drawRect(x, y, width, height, texture);
I just pretend glScale as glRotate as of rotating on its center, it somewhat work but I can see the little adjustments on its coordinate when scaling to other value.
And also, which is better to do, glTranslate or just apply variables such as x,y on vertices. I can't see no difference when switching from those two but I am worrying about adding the "pushing and popping matrices" will affect the behavior of other objects on the scene and performance of my program, because I will use lots of this rectangles.
Update:
So you can visualize how simply I want to achieve
I suppose that <x,y,0> is the position of the bottom left corner of your rectangle in the "canonical" coordinate system (I mean the one we start with).
With these assumptions, you may achieve your goal by resetting the modelview stack to identity, and then move to the object space, before doing the scaling. So you are indeed pretty close, but depending on what you did before with the modelview matrix, you could experience variations in the outcome.
The following code should do what you want:
glPushMatrix();
glLoadIdentity();
glTranslatef(x, y, 0);
// now in "object space"
glScalef(scaleX, scaleY, 0);
drawRect(0, 0, width, height, texture);
glPopMatrix();
I don't know what the draw function does, but I suppose that it just emits a bunch of glVertex and glTexCoord calls, ie. it does not meddle with the modelview matrix, otherwise my code might well break it.
Note that if you wrap all object rendering with glPushMatrix and glPopMatrix calls, you should not need the glLoadIdentity call, and it might even be counter productive. For instance, if you organize your object data as a hierarchy, with each sub object being relatively positioned to its container, then you will need to remove that call completely while recursively rendering the object hierarchy.
Another concern is the one of efficiency. Saving and restoring matrices are fairly costly operations. Given that your question code is using immediate mode, I supposed that it was not your main concern. It will certainly be faster to apply the object transformation by hand (that is, by computing them with your own matrix library), and submit them to opengl without any call to the opengl modelview manipulation routines. However That should be covered by another (more math oriented) question and answer.
The general pattern for a rotation by angle phi (applies to other affine transformations as well) that keeps the point (x,y) fixed is
TRANSLATE(-x, -y)
ROTATE(phi)
TRANSLATE(x, y)
Transformations are applied in order from top to bottom. So you're moving the point (x,y) into the origin at (0,0). It will thus not be affected by the actual rotation. When you're done, the second translation reverses the effect of the first.
This is not limited to OpenGL, but rather applies to any type of graphics processing that supports affine transformations (through matrices or quaternions).
Suppose I have the following code:
glRotatef(angle, 1.0f, 1.0f, 0.0f);
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glRotatef(angle, 0.0f, 0.0f, 1.0f);
glTranslatef(0.0f, 0.0f -5.0f);
Is this less efficient than utilizing one's own custom matrix via the glLoadMatrix function that accomplishes the same functionality?
Also, I know that when multiplying matrices to form a custom linear transformation, the last matrix multiplied is the first transformation to take place. Likewise, is this the case if I utilize the above code? Will it translate, then rotate about the Z axis, followed by rotations about the y and x axes?
In general if you assemble your matrix on your own and load it via glLoadMatrix or glMultMatrix your program will run faster. Unless you make stupid mistakes in your own matrix routines that ruin the performance of course.
This is because the glRotate glTranslate etc. functions do quite a bit more than the pure math. They have to check the matrix-mode. glRotate has to deal with cases where the axis is not passed as a unit-vector etc.
But unless you do this 10thousands times per frame I wouldn't worry about the lost performance. It adds up, but it's not that much.
My personal way of dealing with openGL transformations is to build the matrices in my code and only upload them to OpenGL via glLoadMatrix. This allows me to do lots of shortcuts like reversing the order of multiplications (faster to calculate than the way OpenGL does it). Also it gives me instant access to the matrix which is required if you want to do boundary box checks before rendering.
Needless to say code written with such an approach is also easier to port onto a different graphics API (think OpenGL|ES2, DirectX, Game-Consoles...)
According to the OpenGL specs the glRotate and glTranslate are using their parameters to produce a 4x4 matrix, then the current matrix is multiplied by the (glRotate or glTranslate) produced matrix with the product replacing the current matrix.
This roughly means that in your enlisted code you have 4 matrix multiplications! On top of that you have 4 API calls and a few other calculations that convert the angles of glRotate to a 4x4 matrix.
By using glLoadMatrix you will have to produce the transformation matrix yourself. Having the angles and the translation there are way more efficient ways to produce that transformation matrix and thus speedup the whole thing.
Is this less efficient than utilizing one's own custom matrix via the glLoadMatrix function that accomplishes the same functionality?
Very likely. However if you're running into a situation where setting of the transformation matrices has become a bottleneck you're doing something fundamentally wrong. In a sanely written realtime graphics program calculation of the transformation matrices should make only a very small amount of the things processed in total.
A example for very bad programming was something like this (pseudocode):
glMatrixMode(GL_MODELVIEW)
for q in quads:
glPushMatrix()
glTranslatef(q.x, q.y, q.z)
glBindTexture(GL_TEXTURE_2D, q.texture)
glBegin(GL_QUADS)
for v in [(0,0), (1,0), (1,1), (0,1)]:
glVertex2f(v[0], v[1]
glEnd()
glPopMatrix()
Code like this will perform very poorly. First you're spending an awful lot of time in calculating the new transformation matrix for each quad, then you restart a primitive batch for each quad, the texture switches kill the caches and last but not least its using immediate mode. Indeed the above code is the the worst of all OpenGL anti-patterns in one single example.
Your best bet for increasing rendering performance is to avoid any of the patterns you can see in above example.
Those matrix functions are implemented in the driver, so they might be optimized. You will have to spend some time to write your own code and test if the performance is better or not than the original OpenGL code.
On the other hand in "new" version of OpenGL all of those functions are missing and marked as deprecated. So in new standard you are forced to use custom math functions (assuming that you are using Core profile)
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.
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