OpenGL Combining Yaw Pitch Roll - c++

I'm trying to render water with reflection and refraction and I am new on OpenGL and I have stumbled upon a simple problem. I want for the reflection texture to move the camera down and invert it to capture the image. I have a Camera with quaternions and Yaw and Pitch. I thought to add roll also and rotate roll by 180 degrees to get the inversion but I can not manage to combine the 3 quaternions. Here is the update function of the camera :
void UpdateCameraVectors()
{
// Yaw
glm::quat aroundY = glm::angleAxis(glm::radians(-RightAngle), glm::vec3(0, 1, 0));
// Pitch
glm::quat aroundX = glm::angleAxis(glm::radians(UpAngle), glm::vec3(1, 0, 0));
// Roll
glm::quat aroundZ = glm::angleAxis(glm::radians(RollAngle), glm::vec3(0, 0, 1));
Orientation = aroundY * aroundX;
glm::quat qF = Orientation * glm::quat(0, 0, 0, -1) * glm::conjugate(Orientation);
Front = { qF.x, qF.y, qF.z };
Right = glm::normalize(glm::cross(Front, glm::vec3(0, 1, 0)));
}
Any suggestions on how to invert the view or how to combine the quaternions? I already tried all possible multiplications between them.

Related

GLM LookAt with different coordinate system

I am using GLM to make a LookAt matrix. I use the normal OpenGL coordinate system, but with the Z axis going inwards which is the opposite of the OpenGL standard. Thus, the LookAt function requires some changes:
glm::vec3 pos = glm::vec3(0, 0, -10); // equal to glm::vec3(0, 0, 10) in standard coords
glm::quat rot = glm::vec3(0.991445, 0.130526, 0, 0); // 15 degrees rotation about the x axis
glm::vec3 resultPos = pos * glm::vec3(1, 1, -1); // flip Z axis
glm::vec3 resultLook = pos + (glm::conjugate(rot) * glm::vec3(0, 0, 1)) * glm::vec3(1, 1, -1); // rotate unit Z vec and then flip Z
glm::vec3 resultUp = (glm::conjugate(rot) * glm::vec3(0, 1, 0)) * glm::vec3(1, 1, -1); // same thing as resultLook but with unit Y vec
glm::mat4 lookAt = glm::lookAt(resultPos, resultLook, resultUp)
However, that is a lot of calculation for just flipping a single axis. What do I need to do to get a view matrix which has a flipped Z axis?

Rotation in OpenGL has different effect each time

I am trying to learn OpenGL by coding some stuff, but am still not able to understand the concept of rotation.
Here is my code:
glm::mat4 projection1 = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view1 =camera.GetViewMatrix();//// //
ourShader.setMat4("projection", projection1);
ourShader.setMat4("view", view1);
ourShader.setInt ("pass1",1);
glm::mat4 model1 = glm::mat4(1.0f);
vangle+=0.1;
float cvangle = (vangle-90)*PI /180;
model1=glm::translate (model1 ,glm::vec3(cos(cvangle )*50,0,sin(cvangle )*50));
model1 = glm::scale(model1, glm::vec3(1,1, 1));
model1 = glm::rotate(model1,3.0f , glm::vec3(1, 0, 0));
model1 = glm::rotate(model1,2.0f, glm::vec3(0, 1, 0));
ourShader.setMat4("model", model1);
ourModel.Draw(ourShader);
The helicopter should rotate around the camera, but my problem is that the rotation has a different effect in each angle, i.e. at angle 0, it looks like this:
while at angle 90, it looks like this:
My goal is to rotate the helicopter around the camera showing always the same side.
Any help is appreciated.
If you want to rotate an object in place, then you've to dot the rotation before the translation:
model = translate * rotate;
If you want to rotate around a point, then you've to translate the object (by the rotation radius) and then rotate the translated object:
model = rotate * translate
Note, the operations like rotate, scale and translate, define a new matrix and multiply the input matrix by the new matrix.
So In your case the translate has to be done after a rotation (rotate) around the z axis:
vangle+=0.1;
glm::mat4 model1 = glm::mat4(1.0f);
model1 = glm::rotate(model1, glm::radians(vangle), glm::vec3(0, 0, 1));
model1 = glm::translate(model1, glm::vec3(50.0f, 0.0f, 0.0f);
model1 = glm::scale(model1, glm::vec3(1, 1, 1));

Translate the camera along it's forward axis after rotation in OpenGL?

I want to rotate the camera 30° view = glm::rotate(view, glm::radians(-30.0f), glm::vec3(1, 0, 0)); and then move it forward along the new forward axis view = glm::translate(view, glm::vec3(0, 0, 1));. Is this hard to achieve without having to use glm::lookAt function?

Quaternion-based First Person View Camera

I have been learning OpenGL by following the tutorial, located at https://paroj.github.io/gltut/.
Passing the basics, I got a bit stuck at understanding quaternions and their relation to spatial orientation and transformations, especially from world- to camera-space and vice versa. In the chapter Camera-Relative Orientation, the author makes a camera, which rotates a model in world space relative to the camera orientation. Quoting:
We want to apply an orientation offset (R), which takes points in camera-space. If we wanted to apply this to the camera matrix, it would simply be multiplied by the camera matrix: R * C * O * p. That's nice and all, but we want to apply a transform to O, not to C.
My uneducated guess would be that if we applied the offset to camera space, we would get the first-person camera. Is this correct? Instead, the offset is applied to the model in world space, making the spaceship spin relative to that space, and not to camera space. We just observe it spin from camera space.
Inspired by at least some understanding of quaternions (or so I thought), I tried to implement the first person camera. It has two properties:
struct Camera{
glm::vec3 position; // Position in world space.
glm::quat orientation; // Orientation in world space.
}
Position is modified in reaction to keyboard actions, while the orientation changes due to mouse movement on screen.
Note: GLM overloads * operator for glm::quat * glm::vec3 with the relation for rotating a vector by a quaternion (more compact form of v' = qvq^-1)
For example, moving forward and moving right:
glm::vec3 worldOffset;
float scaleFactor = 0.5f;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
worldOffset = orientation * (axis_vectors[AxisVector::AXIS_Z_NEG]); // AXIS_Z_NEG = glm::vec3(0, 0, -1)
position += worldOffset * scaleFactor;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
worldOffset = orientation * (axis_vectors[AxisVector::AXIS_X_NEG]); // AXIS_Z_NEG = glm::vec3(-1, 0, 0)
position += worldOffset * scaleFactor;
}
Orientation and position information is passed to glm::lookAt matrix for constructing the world-to-camera transformation, like so:
auto camPosition = position;
auto camForward = orientation * glm::vec3(0.0, 0.0, -1.0);
viewMatrix = glm::lookAt(camPosition, camPosition + camForward, glm::vec3(0.0, 1.0, 0.0));
Combining model, view and projection matrices and passing the result to vertex shader displays everything okay - the way one would expect to see things from the first-person POV. However, things get messy when I add mouse movements, tracking the amount of movement in x and y directions. I want to rotate around the world y-axis and local x-axis:
auto xOffset = glm::angleAxis(xAmount, axis_vectors[AxisVector::AXIS_Y_POS]); // mouse movement in x-direction
auto yOffset = glm::angleAxis(yAmount, axis_vectors[AxisVector::AXIS_X_POS]); // mouse movement in y-direction
orientation = orientation * xOffset; // Works OK, can look left/right
orientation = yOffset * orientation; // When adding this line, things get ugly
What would the problem be here?
I admit, I don't have enough knowledge to debug the mouse movement code properly, I mainly followed the lines, saying "right multiply to apply the offset in world space, left multiply to do it in camera space."
I feel like I know things half-way, drawing conclusions from a plethora of e-resources on the subject, while getting more educated and more confused at the same time.
Thanks for any answers.
To rotate a glm quaternion representing orientation:
//Precomputation:
//pitch (rot around x in radians),
//yaw (rot around y in radians),
//roll (rot around z in radians)
//are computed/incremented by mouse/keyboard events
To compute view matrix:
void CameraFPSQuaternion::UpdateView()
{
//FPS camera: RotationX(pitch) * RotationY(yaw)
glm::quat qPitch = glm::angleAxis(pitch, glm::vec3(1, 0, 0));
glm::quat qYaw = glm::angleAxis(yaw, glm::vec3(0, 1, 0));
glm::quat qRoll = glm::angleAxis(roll,glm::vec3(0,0,1));
//For a FPS camera we can omit roll
glm::quat orientation = qPitch * qYaw;
orientation = glm::normalize(orientation);
glm::mat4 rotate = glm::mat4_cast(orientation);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -eye);
viewMatrix = rotate * translate;
}
If you want to store the quaternion, then you recompute it whenever yaw, pitch, or roll changes:
void CameraFPSQuaternion::RotatePitch(float rads) // rotate around cams local X axis
{
glm::quat qPitch = glm::angleAxis(rads, glm::vec3(1, 0, 0));
m_orientation = glm::normalize(qPitch) * m_orientation;
glm::mat4 rotate = glm::mat4_cast(m_orientation);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -eye);
m_viewMatrix = rotate * translate;
}
If you want to give a rotation speed around a given axis, you use slerp:
void CameraFPSQuaternion::Update(float deltaTimeSeconds)
{
//FPS camera: RotationX(pitch) * RotationY(yaw)
glm::quat qPitch = glm::angleAxis(m_d_pitch, glm::vec3(1, 0, 0));
glm::quat qYaw = glm::angleAxis(m_d_yaw, glm::vec3(0, 1, 0));
glm::quat qRoll = glm::angleAxis(m_d_roll,glm::vec3(0,0,1));
//For a FPS camera we can omit roll
glm::quat m_d_orientation = qPitch * qYaw;
glm::quat delta = glm::mix(glm::quat(0,0,0,0),m_d_orientation,deltaTimeSeconds);
m_orientation = glm::normalize(delta) * m_orientation;
glm::mat4 rotate = glm::mat4_cast(orientation);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -eye);
viewMatrix = rotate * translate;
}
The problem lied with the usage of glm::lookAt for constructing the view matrix. Instead, I am now constructing the view matrix like so:
auto rotate = glm::mat4_cast(entity->orientation);
auto translate = glm::mat4(1.0f);
translate = glm::translate(translate, -entity->position);
viewMatrix = rotate * translate;
For translation, I'm left multiplying with an inverse of orientation instead of orientation now.
glm::quat invOrient = glm::conjugate(orientation);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
worldOffset = invOrient * (axis_vectors[AxisVector::AXIS_Z_NEG]);
position += worldOffset * scaleFactor;
}
...
Everything else is the same, apart from some further offset quaternion normalizations in the mouse movement code.
The camera now behaves and feels like a first-person camera.
I still don't properly understand the difference between view matrix and lookAt matrix, if there is any. But that's the topic for another question.

Rotating camera lookAt point with quarternions

I am trying to rotate the camera using quarternions but i have problems doing it.
The first thing that I notices now is that when I execute this the Camera Position and Camera LookAt become almost the same and in some cases they are the same and then i get precision problems and all other problems relating to it when i try and move the camera.
if (Input::getInstance()->isMouseDown(SDL_BUTTON_RIGHT-1)){
//log_.debug("Camera Mouse Left down");
glm::vec2 mouseDelta = glm::ivec2(oldX, oldY) - Input::getInstance()->getMousePosition();
glm::quat q1 = glm::quat(glm::vec3(glm::radians(mouseDelta.y), glm::radians(mouseDelta.x), 0.0f));
cameraLook_ = q1 * (direction * mouseSensitivity_) * glm::conjugate(q1) + cameraPosition_;
//cameraLook_ = glm::rotate(cameraLook_, mouseDelta.x * delta, glm::vec3(0,1,0));
//cameraLook_ = glm::rotate(cameraLook_, mouseDelta.y * delta, glm::vec3(0, 0, 1));
}
I switched back to matrices for my solution, because for me they are easier to work with at the moment.
There are few things i need to understand about quarternions then I can fix my old problem.
glm::mat4 rotationMatrix = glm::translate(cameraPosition_ - glm::vec3(1.0));
rotationMatrix *= glm::rotate(mouseDelta.x, glm::vec3(0, 1, 0));
rotationMatrix *= glm::rotate(mouseDelta.y, glm::vec3(0, 0, 1));
rotationMatrix *= glm::translate(-cameraPosition_ + glm::vec3(1.0));
cameraLook_ = glm::vec3(rotationMatrix * glm::vec4(cameraLook_, 1.0f));