Cross Product Confusion - c++

I have a question regarding a tutorial that I have been following on the rotation of the camera's view direction in OpenGL.
Whilst I appreciate that prospective respondents are not the authors of the tutorial, I think that this is likely to be a situation which most intermediate-experienced graphics programmers have encountered before so I will seek the advice of members on this topic.
Here is a link to the video to which I refer: https://www.youtube.com/watch?v=7oNLw9Bct1k.
The goal of the tutorial is to create a basic first person camera which the user controls via movement of the mouse.
Here is the function that handles cursor movement (with some variables/members renamed to conform with my personal conventions):
glm::vec2 Movement { OldCursorPosition - NewCursorPosition };
// camera rotates on y-axis when mouse moved left/right (orientation is { 0.0F, 1.0F, 0.0F }):
MVP.view.direction = glm::rotate(glm::mat4(1.0F), glm::radians(Movement.x) / 2, MVP.view.orientation)
* glm::vec4(MVP.view.direction, 0.0F);
glm::vec3 RotateAround { glm::cross(MVP.view.direction, MVP.view.orientation) };
/* why is camera rotating around cross product of view direction and view orientation
rather than just rotating around x-axis when mouse is moved up/down..? : */
MVP.view.direction = glm::rotate(glm::mat4(1.0F), glm::radians(Movement.y) / 2, RotateAround)
* glm::vec4(MVP.view.direction, 0.0F);
OldCursorPosition = NewCursorPosition;
What I struggle to understand is why obtaining the cross product is even required. What I would naturally expect is for the camera to rotate around the y-axis when the mouse is moved from left to right, and for the camera to rotate around the x-axis when the mouse is moved up and down. I just can't get my head around why the cross product is even relevant.
From my understanding, the cross product will return a vector which is perpendicular to two other vectors; in this case that is the cross product of the view direction and view orientation, but why would one want a cross product of these two vectors? Shouldn't the camera just rotate on the x-axis for up/down movement and then on the y-axis for left/right movement...? What am I missing/overlooking here?
Finally, when I run the program, I can't visually detect any rotation on the z-axis despite the fact that the rotation scalar 'RotateAround' has a z-value greater than or less than 0 on every call to the the function subsequent to the first (which suggests that the camera should rotate at least partially on the z-axis).
Perhaps this is just due to my lack of intuition, but if I change the line:
MVP.view.direction = glm::rotate(glm::mat4(1.0F), glm::radians(Movement.y) / 2, RotateAround)
* glm::vec4(MVP.view.direction, 0.0F);
To:
MVP.view.direction = glm::rotate(glm::mat4(1.0F), glm::radians(Movement.y) / 2, glm::vec3(1.0F, 0.0F, 0.0F))
* glm::vec4(MVP.view.direction, 0.0F);
So that the rotation only happens on the x-axis rather than partially on the x-axis and partially on the z-axis, and then run the program, I can't really notice much of a difference to the workings of the camera. It feels like maybe there is a difference but I can't articulate what this is.

The problem here is frame of reference.
rather than just rotating around x-axis when mouse is moved up/down..?
What you consider x axis? If that's an axis of global frame of reference or paralleled one, then yes. If that's x axis for frame of reference, partially constricted by camera's position, then, in general answer is no. Depends on order of rotations are done and if MVP gets saved between movements.
Provided that in code her MVP gets modified by rotation, this means it gets changed. If Camera would make 180 degrees around x axis, the direction of x axis would change to opposite one.
If camera would rotate around y axis (I assume ISO directions for ground vehicle), direction would change as well. If camera would rotate around global y by 90 degrees, then around global x by 45 degrees, in result you'll see that view had been tilted by 45 degrees sideways.
Order of rotation around constrained frame of reference for ground-bound vehicles (and possibly, for character of classic 3d shooter) is : around y, around x, around z. For aerial vehicles with airplane-like controls it is around z, around x, around y. In orbital space z and x are inverted, if I remember right (z points down).

You have to do the cross product because after multiple mouse moves the camera is now differently oriented. The original x-axis you wanted to rotate around is NOT the same x-axis you want to rotate around now. You must calculate the vector that is currently pointed straight out the side of the camera and rotate around that. This is considered the "right" vector. This is the cross product of the view and up vectors, where view is the "target" vector (down the camera's z axis, where you are looking) and up is straight up out of the camera up the camera's y-axis. These axes must be updated as the camera moves. Calculating the view and up vectors does not require a cross product as you should be applying rotations to these depending on your movements along the way. The view and up should update by rotations, but if you want to rotate around the x-axis (pitch) you must do a cross product.

Related

Correct camera transformation for first person camera

I am making a camera in openGl and I am having troubles with first person camera. So I had a few versions of camera transformation and all of them had their own problems. So at first, I was doing transformations in this order: I would first translate the object in the positive direction when trying to move away from it and I would translate it in the negative direction when trying to move towards it. After this translation, I would perform rotations arround X and Y axis. Now, when I try to use this camera, I found out that when I have objects in my scene, lets say a few cubes, and when I rotate, everything is fine, but when after this rotation I try translation, all of the objects converge to me or better to say, towards the "player". So after I gave this some thought I realized that because I am doing translations first, in the next frame when I try to translate the player in the direction in which the camera is looking at that moment, what happens is, objects get translated first and then rotated so I get, as a result of this, movement of the objects towards or away from the player. Code for this is here (and dont mind camUp and camRight vectors, these are just y and x axis vectors and are not transformed at all):
m_ViewMatrix = inverse(glm::rotate(glm::mat4(1.0f), m_Rotation, camUp))* inverse(glm::rotate(glm::mat4(1.0f), m_TiltRotation, camRight)) * glm::translate(glm::mat4(1.0f), m_Position);
But option to rotate and then translate is not good because then I get editor sort of camera which is actually fine but that is not what I want.
So I thought about it some more and tried to make small transformations and then reset the parameters, acumulating all the transformations in this way:
m_ViewMatrix = inverse(glm::rotate(glm::mat4(1.0f), m_Rotation, camUp)) * glm::translate(glm::mat4(1.0f), m_Position)* inverse(glm::rotate(glm::mat4(1.0f), m_TiltRotation, camRight))*m_ViewMatrix;
m_Position = { 0.0f, 0.0f, 0.0f };
m_Rotation = 0.0f;
m_TiltRotation = 0.0f;
But now I have a problem with rotations arround z axis which I don't want. This problem was not there before. So now I have no idea what to do, I read some answers here but couldn't apply them I don't know why. So if anyone could help me in the context of the code I just copied here, that would be great.

Finding angles in each axis from vertical normal

I am making program which reads texture that should be applied to the mesh and generates some shapes which should be displayed on their triangles. I am converting points in a way that originally shape appears to be lying on XZ (in openGL way of marking axes, so Y is vertical, Z goes towards camera, X to the right). Now I have no idea how to properly measure angle between actual normal of traingle and vertical normal (I mean (0, 1, 0)) of image. I know, that it's probably basic, but my mind refuses to cooperate on 3D graphics tasks recently.
Currently I use
angles.x = glm::orientedAngle(glm::vec2(normalOfTriangle.z, normalOfTriangle.y), glm::vec2(1.0f, 0.0f));
angles.y = glm::orientedAngle(glm::vec2(normalOfTriangle.x, normalOfTriangle.z), glm::vec2(1.0f, 0.0f));
angles.z = glm::orientedAngle(glm::vec2(normalOfTriangle.x, normalOfTriangle.y), glm::vec2(1.0f, 0.0f));
angles = angles + glm::vec3(-glm::half_pi<float>(), 0.0f, glm::half_pi<float>());
Which given my way of thinking should give proper results, but the faces of cube that should have normal parallel to Z axis appear to be unrotated in Z.
My logic bases on that I measure angle from each axis, and then rotate each axis by such angle for it to be vertical. But as I said, my mind glitches, and I cannot find proper way to do it. Can somebody please help?

cursor orientation openGL c++

I want my 2D sprite to rotate while always facing my cursor.
I am using glad, SDL2 & glm for the math.
the "original" way I tried was to calculate the angle between my Front and my desired LookAt vector of the object and put that angle in degrees into an glm::rotate matrix.
That did not work out for some strange reason.
The other way was to do it within a quat and apply the quat to my model matrix, which did not help either.
My object is rendered with its center at the origin (0,0,0) - so no translation needs to be done for the rotation.
I draw 2 triangles to make a rectangle on which I load my texture.
My model matrix looks like that in theory:
model = rotate * scale;
I then plug it into the shader (where Position is my vec3 Vertex)
position = projection * view * model * vec4(Position, 1.0f);
The first strange thing is, if I hardcode 90.0f as an angle into glm::rotate, my object is actually rotated about 120° clockwise.
If I plug in 80° it actually rotates about ~250° clockwise.
If I plug in 45° it's a perfect 45° clockwise rotation.
All rotations are around the z-axis, eg.:
model = glm::rotate(model, 90.0f, glm::vec3(0.0f,0.0f,1.0f);
If I use a quaternion to simulate an orientation, it gives me angles between 0,2&0,9 radians and my object seems only to rotate between 0.0° & 45° clockwise, no matter where I put my cursor.
If I calculate the angle btw. my two vectors (ObjectLookAt & MousePosition) and store them I get also quite correct angles, but the glm::rotate function does not work as I'd expected.
Finally if I simply code the angle as:
float angle = static_cast<float>(SDL_GetTicks()/1000);
Which starts by one it actually rotates even more weird.
I'd expect it to start to rate by 1° (as it starts with 1 second) and then rotate a full circle around the z axis until there are 360 seconds over.
However it rotates full 360° in about 6 second. so ever "1" that is added on the angle and plugged into glm::rotate as a degree represents 60°?
Is this now a flaw in my logic? Do I not rotate a sprite around the z-axis if it is drawn on a x-y plane?
I also tried the x & y axis just to be safe here, but that didn't work.
I am really stuck here, I (think I) get how it should work in theory, especially as it all happens in "2D", but I cannot get it work..
The first strange thing is, if I hardcode 90.0f as an angle into glm::rotate, my object is actually rotated about 120° clockwise. If I plug in 80° it actually rotates about ~250° clockwise. If I plug in 45° it's a perfect 45° clockwise rotation.
This is, because the function glm::rotate expects the angle in radians (since GLM version 0.9.6).
Adapt your code like this:
model = glm::rotate(model, glm::radians(angel_degrees), glm::vec3(0.0f,0.0f,1.0f);
see also:
glm rotate usage in Opengl
GLM::Rotate seems to cause wrong rotation?
GLM: function taking degrees as a parameter is deprecated (WHEN USING RADIANS)

OpenGL Transforming an object on it's local coordinate system based on rotation

So at the moment am working on a game for my coursework which is based around the idea of flying a rocket, I spent too much time thinking about the physics behind it that I completely ignored getting it to move properly.
For example when I were to draw a cone with the top pointing to the sky, and I rotate it on the X axis it rotates properly however if I translate it on the Y axis it moves on the global Y axis instead on it's local coordinate system which would have the Y axis pointing out of the cone's top.
My question is does openGL have a local coordinate system or would I have to somehow make my own transformation matrices, and if so how would I go about doing that.
The way I am doing the transformation and rotation is as follows:
glPushMatrix();
glTranslatef(llmX, llmY + acceleration, llmZ);
glRotatef(rotX, 1.0f, 0.0f, 0.0f);
glRotatef(rotY, 0.0f, 0.0f, 1.0f);
drawRocket();
glPopMatrix();
Here is a picture better explaining what I mean hopefully offers a better explanation.
EDIT: I find it really weird that the rotations seem to work one after the other as in if I rotate it on the X axis once and then proceed to rotate it on the Z axis it rotates from the already rotated X axis instead of the world X axis.
Hoping somebody could help me with understanding this, really need to get it working for my project.
Thank you.
If you are using a translation matrix for moving up (i.e. moving in positive Y direction), no matter where you are in on the matrix stack or in the transformation process, you are going to move the vertices in the positive Y direction.
If you instead want it move in the rotated direction, I suggest translating along the Y axis first, and then rotate to your desired angle. Essentially, push the matrices in the opposite fashion.

OpenGL camera rotation

In OpenGL I'm trying to create a free flight camera. My problem is the rotation on the Y axis. The camera should always be rotated on the Y world axis and not on the local orientation. I have tried several matrix multiplications, but all without results. With
camMatrix = camMatrix * yrotMatrix
rotates the camera along the local axis. And with
camMatrix = yrotMatrix * camMatrix
rotates the camera along the world axis, but always around the origin. However, the rotation center should be the camera. Somebody an idea?
One of the more tricky aspects of 3D programming is getting complex transformations right.
In OpenGL, every point is transformed with the model/view matrix and then with the projection matrix.
the model view matrix takes each point and translates it to where it should be from the point of view of the camera. The projection matrix converts the point's coordinates so that the X and Y coordinates can be mapped to the window easily.
To get the mode/view matrix right, you have to start with an identity matrix (one that doesn't change the vertices), then apply the transforms for the camera's position and orientation, then for the object's position and orientation in reverse order.
Another thing you need to keep in mind is, rotations are always about an axis that is centered on the origin (0,0,0). So when you apply a rotate transform for the camera, whether you are turning it (as you would turn your head) or orbiting it around the origin (as the Earth orbits the Sun) depends on whether you have previously applied a translation transform.
So if you want to both rotate and orbit the camera, you need to:
Apply the rotation(s) to orient the camera
Apply translation(s) to position it
Apply rotation(s) to orbit the camera round the origin
(optionally) apply translation(s) to move the camera in its set orientation to move it to orbit around a point other than (0,0,0).
Things can get more complex if you, say, want to point the camera at a point that is not (0,0,0) and also orbit that point at a set distance, while also being able to pitch or yaw the camera. See here for an example in WebGL. Look for GLViewerBase.prototype.display.
The Red Book covers transforms in much more detail.
Also note gluLookAt, which you can use to point the camera at something, without having to use rotations.
Rather than doing this using matrices, you might find it easier to create a camera class which stores a position and orthonormal n, u and v axes, and rotate them appropriately, e.g. see:
https://github.com/sgolodetz/hesperus2/blob/master/Shipwreck/MapEditor/GUI/Camera.java
and
https://github.com/sgolodetz/hesperus2/blob/master/Shipwreck/MapEditor/Math/MathUtil.java
Then you write things like:
if(m_keysDown[TURN_LEFT])
{
m_camera.rotate(new Vector3d(0,0,1), deltaAngle);
}
When it comes time to set the view for the camera, you do:
gl.glLoadIdentity();
glu.gluLookAt(m_position.x, m_position.y, m_position.z,
m_position.x + m_nVector.x, m_position.y + m_nVector.y, m_position.z + m_nVector.z,
m_vVector.x, m_vVector.y, m_vVector.z);
If you're wondering how to rotate about an arbitrary axis like (0,0,1), see MathUtil.rotate_about_axis in the above code.
If you don't want to transform based on the camera from the previous frame, my suggestion might be just to throw out the matrix compounding and recalc it every frame. I don't think there's a way to do what you want with a single matrix, as that stores the translation and rotation together.
I guess if you just want a pitch/yaw camera only, just store those values as two floats, and then rebuild the matrix based on that. Maybe something like pseudocode:
onFrameUpdate() {
newPos = camMatrix * (0,0,speed) //move forward along the camera axis
pitch += mouse_move_x;
yaw += mouse_move_y;
camMatrix = identity.translate(newPos)
camMatrix = rotate(camMatrix, (0,1,0), yaw)
camMatrix = rotate(camMatrix, (1,0,0), pitch)
}
rotates the camera along the world axis, but always around the origin. However, the rotation center should be the camera. Somebody an idea?
I assume matrix stored in memory this way (number represent element index if matrix were a linear 1d array):
0 1 2 3 //row 0
4 5 6 7 //row 1
8 9 10 11 //row 2
12 13 14 15 //row 3
Solution:
Store last row of camera matrix in temporary variable.
Set last row of camera matrix to (0, 0, 0, 1)
Use camMatrix = yrotMatrix * camMatrix
Restore last row of camera matrix from temporary variable.