GLM LookAt with different coordinate system - c++

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?

Related

lookAt that returns camera matrix instead of view matrix

I can generate the camera matrix as follows:
void lookAt(vec3 center) {
vec3 f = normalize(center - this->eye);
vec3 u(0, 1, 0);
vec3 r = normalize(cross(f, u));
u = cross(r, f);
this->cameraMatrix = inverse(mat4(
r.x, u.x, -f.x, 0,
r.y, u.y, -f.y, 0,
r.z, u.z, -f.z, 0,
-dot(r, this->eye), -dot(u, this->eye), dot(f, this->eye), 1
));
// update MVP
}
I then update my MVP matrix, using V = inverse(this->cameraMatrix). I want to store the camera matrix so I can do easy translations/rotations.
The above code works but isn't very efficient. I don't understand the maths enough, but I was hoping for a way to directly calculate the cameraMatrix, given f, u, r, this->eye.
Thanks
Given the camera position (eye), the camera target (center), and the up vector (upVector), the matrix that defines the position and orientation of the orientation can be calculated in a right-handed system where the x-axis is to the left, the y-axis is the up-vector, and the z-axis is points in the opposite direction of the line of sight, as follows:
glm::vec3 zAxis = glm::normalize(eye - center);
glm::vec3 xAxis = glm::normalize(glm::cross(upVector, zAxis));
glm::vec3 yAxis = glm::cross(zAxis, xAxis);
glm::mat4 cameraMatrix = glm::mat4(
glm::vec4(xAxis, 0),
glm::vec4(yAxis, 0),
glm::vec4(zAxis, 0),
glm::vec4(eye, 1.0f));
This is a matrix that transforms from view space to world space.

OpenGL Combining Yaw Pitch Roll

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.

Modern OpenGL: How to get the vector position of the cube?

glm::mat4 yellow_bone_obj_mat = m_bone_animation->get_yellow_mat();
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(yellow_bone_obj_mat));
bone_obj->obj_color = m_bone_animation->colors[1];
draw_object(shader, *bone_obj);
I created a cube using this code.
glm::vec3 scale = glm::vec3(1.f, 1.f, 1.f);
m_yellow_mat = glm::mat4(1.0f);
m_yellow_mat = glm::scale(m_yellow_mat, scale);
glm::vec3 pivot = glm::vec3(0.0f, 2.f, 0.0f);
glm::vec3 pos = root_position;
m_yellow_mat = glm::translate(m_yellow_mat, pos);
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(angleZ), glm::vec3(0, 0, 1));
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(angleY), glm::vec3(0, 1, 0));
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(angleX), glm::vec3(1, 0, 0));
m_yellow_mat = glm::translate(m_yellow_mat, pivot);
m_yellow_mat = glm::scale(m_yellow_mat, scale_vector[1]);
// scale_vector[1] = {0.5f,4.f,0.5f} This is scale_vector[1]
// root_position = { 2.0f,1.0f,2.0f };
These are the transformations I applied.
This enables it to rotate around the endpoint (bottom part) of the cube. I want to find the Vector position of the start point of the cube (top part). How can I do that?
A 4x4 transformation matrix looks as follows:
column 0: Xx, Xy, Xz, 0
column 1: Yx, Xy, Yz, 0
column 2: Zx Zy Zz, 0
column 3: Tx, Ty, Tz, 1
The translation is stored in the 4th column of the column major order matrix.
That means the xyz components of the translation are m_yellow_mat[3][0], m_yellow_mat[3][1] and m_yellow_mat[3][2]:
glm::vec3 trans = glm::vec3(m_yellow_mat[3]);
If you want to know the world position of a vertex coordinate of the model, then you've to transform the model coordinate by the model matrix:
glm::vec3 vertex_corodiante;
glm::vec3 world_coordiante = glm::vec3(m_yellow_mat * glm::vec4(vertex_corodiante, 1.0f));

OpenGl glm local rotation

I need to rotate object in local coordinates system, like you can rotate it in 3dmax\maya etc...
My current code is:
ModelMatrix = glm::mat4(1.0f);
TransformMatrix = glm::mat4(1.0f);
ScaleMatrix = glm::mat4(1.0f);
RotateMatrix = glm::mat4(1.0f);
ScaleMatrix = glm::scale(ScaleMatrix, glm::vec3(scalex, scalez, scaley));
TransformMatrix = glm::translate(TransformMatrix, glm::vec3(x, z, y));
RotateMatrix = glm::rotate(RotateMatrix, anglex, glm::vec3(1, 0, 0));
RotateMatrix= glm::rotate(RotateMatrix, angley, glm::vec3(0, 0, 1));
RotateMatrix = glm::rotate(RotateMatrix, anglez, glm::vec3(0, 1, 0));
ModelMatrix = TransformMatrix * ScaleMatrix* RotateMatrix;
MVP = Projection * View * ModelMatrix ;
anglex,y,z - comes from keyboard.
Right now only last dimension works as local (im my example it's glm::vec3(0, 1, 0) Z axis) At this IMAGE I show what I needed(2) and what I've got(3)... If I changes "anglez" it's always works as ROLL. But anglex and angley is in the world coordinates system.
The second my attempt - use Quaternions:
quat MyQuaternion= glm::quat(cos(glm::radians(xangle / 2)), 0, sin(glm::radians(xangle / 2)), 0);
quat MyQuaternion2 = glm::quat(cos(glm::radians(yangle/ 2)), sin(glm::radians(yangle / 2)), 0, 0);
quat MyQuaternion3 = glm::quat(cos(glm::radians(zangle / 2)), 0,0,sin(glm::radians(zangle / 2)));
glm::mat4 RotationMatrix = toMat4(MyQuaternion*MyQuaternion2*MyQuaternion3);
But I have the same result
You should modify the entire ModelMatrix instead of the angles. Initialize ModelMatrix to the identity matrix. Then, when you process keyboard input:
if(rotate about x-axis)
ModelMatrix = glm::rotate(ModelMatrix, angle, glm::vec3(1, 0, 0));
if(rotate about y-axis)
ModelMatrix = glm::rotate(ModelMatrix, angle, glm::vec3(0, 1, 0));
if(rotate about z-axis)
ModelMatrix = glm::rotate(ModelMatrix, angle, glm::vec3(0, 0, 1));
if(any rotation happened)
MVP = Projection * View * ModelMatrix ;
You can do this modification at any level. Either the MVP level, the ModelMatrix level (as shown here) or the RotateMatrix level.

How do I apply a local/relative rotation to a transform?

I'm writing a simple physics component in my C++ engine, using the GLM math library, and any rotations I apply are done in world space, i.e. each rotation is applied along the global X, Y, and Z axes, no matter which way the object is facing. I am applying a torque to my object, and using that to calculate a rotation amount for each axis.
I add the torque via a call to the AddTorque function, which uses the object's transform to apply it in a relative direction. For example, for pitching the object (rotation around the X axis):
AddTorque(m_transform[0] * 50.0f);
The calculation code itself, where the rotation is not local/relative (m_acceleration, m_velocity, m_torque, etc, are all of the form glm::vec3, and the transform of the type glm::mat4):
void PhysicsComponent::Update(float a_deltaTime)
{
///////////
// rotation
glm::mat4 transform = m_parent->GetTransform();
glm::vec3 rotVec = glm::vec3(0, 0, 0);
m_angularAcceleration = m_torque / m_momentOfInertia;
m_angularVelocity += m_angularAcceleration * a_deltaTime;
rotVec += m_angularVelocity * a_deltaTime;
transform = glm::rotate(transform, rotVec.x, glm::vec3(1, 0, 0));
transform = glm::rotate(transform, rotVec.y, glm::vec3(0, 1, 0));
transform = glm::rotate(transform, rotVec.z, glm::vec3(0, 0, 1));
///////////
// position
glm::vec3 position = transform[3].xyz;
m_acceleration = m_force / m_mass;
m_velocity += m_acceleration * a_deltaTime;
position += m_velocity * a_deltaTime;
transform[3].xyz = position;
m_parent->SetTransform(transform);
m_force.x = 0;
m_force.y = 0;
m_force.z = 0;
m_torque.x = 0;
m_torque.y = 0;
m_torque.z = 0;
rotVec = glm::vec3(0,0,0);
}