I've been playing around for awhile now with directx and can't figure out how to rotate something without rotating it all the way around (0,0,0). The farther I get away from the center of my world the bigger circles in makes during its rotation.
Don't forget the matrix transformations apply to the coordinate system. Let's say you want to move your object upwards on an xy plane by 20 units, and rotate it by 90 degrees. If you rotate by 90 degrees first, you'll be rotating the entire plane by 90 degrees. This means 90 degrees is the new "upwards" when you translate up the y axis.
So, we translate first, so that our object's center is 0,0. Now when we rotate, we should be rotating around the center of the object. Of course, don't forgot to translate back, or clear the matrix somehow.
The order does matter when doing matrix transformations, as I'm sure you know. Usually, you should translate, scale, then rotate.
If you need a rotation α, around a point p located at (x₀,y₀,z₀), you create the matrix :
T(-x₀,-y₀,-z₀) * R(α) * T(x₀,y₀,z₀)
T means Translation and R means rotation. Also, depending on your convention such as row or column matrix, you may have to revert the order of operation.
Related
I am making a Videogame Engine for a College Subject and I implemented a 3d camera icons to show where the gameobjects without mesh but with a component camera are.
https://i.gyazo.com/5cd944b8f1c3d3e08aea4c440d294a36.mp4
Here's how it rotates now. The goal is to make the camera rotate just like now but looking to the frustum front, so i should make the camera mesh rotate 90 degrees to the right.
How can I make my original quaternion rotate 90 degrees to the right? Thanks in advance!
One of the core aspects of why quaternions are used to represent rotations in games (and other applications) is that you can chain them very easily by multiplying them. So, by creating a quaternion that rotates 90 degrees to the right, and multiplying that with your rotation quaternion, you get a quaternion that does both.
Notice that order matters here, so Quaternion(90 degree to the right) * YourQuaternion will yield a different result than YourQuaternion * Quaternion(90 degree to the right), similar to how you end up with a different rotation in the real world, depending on the order you're applying the rotations. In terms of quaternions, the rightmost rotation is "applied first", so your "90 degrees to the right" quaternion should be on the right side of the multiply sign.
I have a basic cube generated in my 3D world. I can rotate correctly around the camera, but when I translate after rotating, the translations are not correct.
For example, if I rotate 90 degrees and translate into the Z axis, it would move as if translating in the X axis.
glLoadIdentity();
glRotatef(angle,0,1,0); //Rotate around the camera.
glTranslatef(movX,movY,movZ); //Translate after rotating around the camera.
glCallList(cubes[0]);
I need some help with this. Also, I tried translating before rotating, but the rotation is not at the camera. It is at the edge of the cube.
Keep in mind that in OpenGL that the transformation is applied to the camera, not the objects rendered; so you observe the inverse of the transformation you expected.
Also in OpenGL the Y and Z axes are flipped (Y is vertical), so you observe a horizontal translation instead of a vertical one.
Also, because the object is rotated though 90 degrees about Y, the X and Z axes replace each other (one of them is reversed).
willywonkadailyblah's answer is half correct. Because you are using the old OpenGL, you're using the old matrix stack. You are modifying the modelview matrix when you're doing your glRotatef and glTranslatef calls. The modelview matrix is actually the model's matrix and the camera's view matrix precombined (already multiplied together). These matrices are what determine where your object is in 3D space and where your viewing position/direction of the world is. So you can think of your calls as moving the camera, but it's probably easier to think of them as moving and rotating the world.
These rotate and translation calls are linear transformations. This has a precise definition, but for our purposes it means that you can represent the transformation as a matrix and you multiply it with the point's coordinates to apply the transformation to a point. Now matrix multiplication is not commutative, meaning AB != BA. All this to say that when you rotate, then translate it is different than translating and rotating, which I think you know. But then when you translate, rotate, and translate again, it might be a little more difficult to follow what you're actually doing. Worse even if you throw in some scaling in there. So I would suggest learning how linear transformations work and maintaining your own matrices for the objects and camera if you're serious about learning OpenGL.
learnopengl.org is an excellent website, but it teaches you Modern OpenGL, not what you're currently using. But the lesson on transformations and on coordinate systems are probably generally helpful, even without exact code for you to follow
I was trying to understand lesson 9 from NEHEs tutorial, which is about bitmaps being moved in 3d space.
the most interesting thing here is to move 2d bitmap texture on a simple quad through 3d space and keep it facing the screen (viewer) all the time. So the bitmap looks 3d but is 2d facing the viewer all the time no matter where it is in the 3d space.
In lesson 9 a list of stars is generated moving in a circle, which looks really nice. To avoid seeing the star from its side the coder is doing some tricky coding to keep the star facing the viewer all the time.
the code for this is as follows: ( the following code is called for each star in a loop)
glLoadIdentity();
glTranslatef(0.0f,0.0f,zoom);
glRotatef(tilt,1.0f,0.0f,0.0f);
glRotatef(star[loop].angle,0.0f,1.0f,0.0f);
glTranslatef(star[loop].dist,0.0f,0.0f);
glRotatef(-star[loop].angle,0.0f,1.0f,0.0f);
glRotatef(-tilt,1.0f,0.0f,0.0f);
After the lines above, the drawing of the star begins. If you check the last two lines, you see that the transformations from line 3 and 4 are just cancelled (like undo). These two lines at the end give us the possibility to get the star facing the viewer all the time. But i dont know why this is working.
And i think this comes from my misunderstanding of how OpenGL really does the transformations.
For me the last two lines are just like undoing what is done before, which for me, doesnt make sense. But its working.
So when i call glTranslatef, i know that the current matrix of the view gets multiplied with the translation values provided with glTranslatef.
In other words "glTranslatef(0.0f,0.0f,zoom);" would move the place where im going to draw my stars into the scene if zoom is negative. OK.
but WHAT exactly is moved here? Is the viewer moved "away" or is there some sort of object coordinate system which gets moved into scene with glTranslatef? Whats happening here?
Then glRotatef, what is rotated here? Again a coordinate system, the viewer itself?
In a real world. I would place the star somewhere in the 3d space, then rotate it in the world space around my worlds origin, then do the moving as the star is moving to the origin and starts at the edge again, then i would do a rotate for the star itself so its facing to the viewer. And i guess this is done here. But how do i rotate first around the worlds origin, then around the star itself? for me it looks like opengl is switching between a world coord system and a object coord system which doesnt really happen as you see.
I dont need to add the rest of the code, because its pretty standard. Simple GL initializing for 3d drawings, the rotating stuff, and then the simple drawing of QUADS with the star texture using blending. Thats it.
Could somebody explain what im misunderstanding here?
Another way of thinking about the gl matrix stack is to walk up it, backwards, from your draw call. In your case, since your draw is the last line, let's step up the code:
1) First, the star is rotated by -tilt around the X axis, with respect to the origin.
2) The star is rotated by -star[loop].angle around the Y axis, with respect to the origin.
3) The star is moved by star[loop].dist down the X axis.
4) The star is rotated by star[loop].angle around the Y axis, with respect to the origin. Since the star is not at the origin any more due to step 3, this rotation both moves the center of the star, AND rotates it locally.
5) The star is rotated by tilt around the X axis, with respect to the origin. (Same note as 4)
6) The star is moved down the Z axis by zoom units.
The trick here is difficult to type in text, but try and picture the sequence of moves. While steps 2 and 4 may seem like they invert each other, the move in between them changes the nature of the rotation. The key phrase is that the rotations are defined around the Origin. Moving the star changes the effect of the rotation.
This leads to a typical use of stacking matrices when you want to rotate something in-place. First you move it to the origin, then you rotate it, then you move it back. What you have here is pretty much the same concept.
I find that using two hands to visualize matrices is useful. Keep one hand to represent the origin, and the second (usually the right, if you're in a right-handed coordinate system like OpenGL), represents the object. I splay my fingers like the XYZ axes to I can visualize the rotation locally as well as around the origin. Starting like this, the sequence of rotations around the origin, and linear moves, should be easier to picture.
The second question you asked pertains to how the camera matrix behaves in a typical OpenGL setup. First, understand the concept of screen-space coordinates (similarly, device-coordinates). This is the space that is actually displayed. X and Y are the vectors of your screen, and Z is depth. The space is usually in the range -1 to 1. Moving an object down Z effectively moves the object away.
The Camera (or Perspective Matrix) is typically responsible for converting 'World' space into this screen space. This matrix defines the 'viewer', but in the end it is just another matrix. The matrix is always applied 'last', so if you are reading the transforms upward as I described before, the camera is usually at the very top, just as you are seeing. In this case you could think of that last transform (translate by zoom) as a very simple camera matrix, that moves the camera back by zoom units.
Good luck. :)
The glTranslatef in the middle is affected by the rotation : it moves the star along axis x' to distance dist, and axis x' is at that time rotated by ( tilt + angle ) compared to the original x axis.
In opengl you have object coordinates which are multiplied by a (a stack of) projection matrix. So you are moving the objects. If you want to "move a camera" you have to mutiply by the inverse matrix of the camera position and axis :
ProjectedCoords = CameraMatrix^-1 . ObjectMatrix . ObjectCoord
I also found this very confusing but I just played around with some of the NeHe code to get a better understanding of glTranslatef() and glRotatef().
My current understanding is that glRotatef() actually rotates the coordinate system, such that glRotatef(90.0f, 0.0f, 0.0f, 1.0f) will cause the x-axis to be where the y-axis was previously. After this rotation, glTranslatef(1.0f, 0.0f, 0.0f) will move an object upwards on the screen.
Thus, glTranslatef() moves objects in accordance with the current rotation of the coordinate system. Therefore, the order of glTranslatef and glRotatef are important in tutorial 9.
In technical terms my description might not be perfect, but it works for me.
I have an object right now which I have moving in a circle around the vertical (Y) axis. I want to rotate this object so it is always aligned with the tangent of the circle, how do I do this? Not sure what combination of sin/cosine/tan to use as the first argument of glRotatef...
Thanks!
The first argument of glRotatef is the angle, in radians (so 0 is no rotation, PI is flipped around end for end, and 2*PI is rotated all the way back to the original orientation).
You probably could have answered this yourself through trial and error in less time than it took to askk the question.
Note that if you choose the center of rotation to be the center of the circle instead of the center of the object, you won't need a separate translation step.
I am trying to achieve the same rotational effect like Maya in my project.
I have some knowledge on quaternions and the trackball example.
Unfortunately I am still unable to wrap my head around the concept of using the quaternions to get the desired effect.
Basically I am still getting the same issue I had before with the 3d trackball. After flipping the object upside down, and then trying to rotate to the right, the object will rotate to the left. Well actually its my camera rotating around the focus point in the opposite direction.
The problem is that I am using the screen coordinates & trackball to get the old / new vectors and getting the angle of rotation from those two vectors. I will always get the wrong axis of rotation this way.
How should I go about solving this issue?
I don't know Maya so I can only guess that its rotation is like this: if you rotate left-right, it feels natural. Then if you rotate the object up-down 180 degrees, then rotate left-right again, it still feels natural.
If you are familiar with the concept of using a matrix to do transformations (like rotate, scale and translate), well a quaternion is just the same concept but it only allows rotations, so you might want to use it to constrain your transforms to just rotations. In practice, you can use either a matrix or a quaternion to do the same thing.
What you need to do is remember the current quaternion state for the object, then when the next frame of rotation occurs, multiply the new rotation with the old quaternion (in that order) to give you the next frame's quaternion. That will ensure that no matter what orientation the object is in, the next frame's rotation will be applied from the viewer's viewpoint. This is as opposed to some naive rotation where you just say "user is scrolling up/down, therefore alter the object's X-axis rotation", which causes that flipping.
Remember, like matrices, quaternions need to be multiplied in reverse order that the actions are actually applied, which is why I said to multiply the new operation by the existing quaternion.
To finish with an example. Let's say the user is going to perform 2 actions:
On frame 1, the user rotates the object 180 degrees about the X axis (up/down rotation).
On frame 2, the user rotates the object 90 degrees about the Y axis (left/right rotation).
Lets say the object has a quaternion Q. Every frame, you will reset the object to its default coordinates and apply the quaternion Q to rotate it. Now you might initialise it with the identity quaternion, but let's just say the initial quaternion is called Q0.
On frame 1, create a new quaternion R1 which is a "rotate 180 degrees about the X axis" quaternion (you can find some maths to compute such a quaternion). Pre-multiply the new operation by the existing quaternion: Q1 = R1 * Q0.
On frame 2, create a new quaternion R2 which is a "rotate 90 degrees about the Y axis" quaternion. Pre-multiply the new operation by the existing quaternion: Q2 = R2 * Q1.
On frame 1 you will use Q1 to display the object, and on frame 2 you will use Q2. You can simply keep applying any subsequent user actions to the quaternion and it will always be rotated in the viewer's frame of reference.
I think you have problems with changing coordinate system.
Suppose, you want to rotate object in X Axis, then in Y Axis, and then move it and scale. So, you should multiply your transformation maxtrix (at the beginning it equals to itentity matrix) to the rotation matrix (firstly to X, then to Y), then to translation matrix and at the end to scaling matrix. So, when your current matrix multiplies to the resulting matrix, your coordinate systems changes.
To avoid this problem you can use 2 methods:
1) to accumulate your resultig matrix as product of all previous matrices.
2) to use stack, where in the top will be the matrix, which equals to product of all matrices in the bottom of this matrix (in the stack).
P.S. I'm not sure, that it helps you. I never used quaternions in my projects.