I want to rotate an object around its local axis. First I calculate the local axis by the transform.rotation vector (x - pitch, y - yaw, z - roll).
glm::vec3 front;
front.x = cos(glm::radians(transform.rotation.y)) * cos(glm::radians(transform.rotation.x));
front.y = sin(glm::radians(transform.rotation.x));
front.z = sin(glm::radians(transform.rotation.y)) * cos(glm::radians(transform.rotation.x));
transform.front = glm::normalize(front);
transform.right = glm::normalize(glm::cross(transform.front, glm::vec3(0.0f, 1.0f, 0.0f)));
transform.up = glm::normalize(glm::cross(transform.right, transform.front));
And then I set the model matrix as follows.
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, transform.position);
model = glm::rotate(model, glm::radians(transform.rotation.x), transform.right);
model = glm::rotate(model, glm::radians(transform.rotation.y), transform.up);
model = glm::rotate(model, glm::radians(transform.rotation.z), transform.front);
model = glm::scale(model, transform.scale);
shader.setMat4("model", model);
The only one that seems to be working is the yaw rotation, the roll performs as pitch and the pitch as roll, and almost any tweak makes the object rotate in any direction but the specified one. The others just not rotate in the expected way.
Am I missing something?
Related
So I'm working on a 3d painting application. I managed to make a basic renderer and model loader.
I created a camera system where I can use it to navigate around the scene(mouse/keyboard) but that's not what I want, so I made that camera static and now I'm trying to rotate/pan/zoom the model itself. I managed to implement panning and zooming. for panning i change the x/y position according to the mouse and for zooming I add or substract from the z-axis according to the mouse scroll.
But now I want to be able to rotate the 3d model with the mouse. Example: When i hold right mouse button and move the mouse up the model should rotate on it's x-axis(pitch) and if i move the mouse to the left/right it should rotate on y-axis(yaw). And I just couldn't do it.
The code bellow I get xpos/ypos of the cursor on the screen, calculate the offset and "trying to rotate the cube". The only problem is that i can't rotate the cuber normally if i move the mouse up the model rotate on the x-axis and y-axis with a little tilt and vice-versa.
This is the code in my rendering loop:
shader.use();
glm::mat4 projection = glm::perspective(glm::radians(45.0f),
(float)SCR_WIDTH/(float)SCR_HEIGHT, 0.01f, 100.0f);
shader.setMat4f("projection", projection);
glm::mat4 view = camera.getViewMatrix();
shader.setMat4f("view", view);
glm::mat4 modelm = glm::mat4(1.0f);
modelm = glm::translate(modelm, object_translation);
// Should rotate cube according to mouse movement
//modelm = glm::rotate(modelm, glm::radians(angle), glm::vec3(0.0f));
shader.setMat4f("model", modelm);
renderer.draw(model, shader);
This is the call where i handle the mouse movement callback:
void mouseCallback(GLFWwindow* window, double xpos, double ypos)
{
if (is_rotating)
{
if (is_first_mouse)
{
lastX = xpos;
lastY = ypos;
is_first_mouse = false;
}
// xpos and ypos are the cursor coords i get those with the
mouse_callback
double xoffset = xpos - lastX;
double yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;
object_rotation.y += xoffset; // If i use yoffset the rotation flips
object_rotation.x += yoffset;
rotation_angle += (xoffset + yoffset) * 0.25f;
}
}
Mouse panning works fine too can't say the same for the rotation.
I fixed it. After some research and asking i was told that u can only do one rotation at a time and i was trying to do both x/y-axis in the same time. Once i seperate the two rotations. object will now rotate on x-axis first then y-axis the problem was solved.
The code should be like this:
shader.use();
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH/(float)SCR_HEIGHT, 0.01f, 100.0f);
shader.setMat4f("projection", projection);
glm::mat4 view = camera.getViewMatrix();
shader.setMat4f("view", view);
glm::mat4 modelm = glm::mat4(1.0f);
modelm = glm::scale(modelm, glm::vec3(1.0f));
modelm = glm::translate(modelm, glm::vec3(0.0f, 0.0f, -5.0f));
// Handle x-axis rotation
modelm = glm::rotate(modelm, glm::radians(object_orientation_angle_x), glm::vec3(object_rotation_x, 0.0f, 0.0f));
// Handle y-axis rotation
modelm = glm::rotate(modelm, glm::radians(object_orientation_angle_y), glm::vec3(0.0f, object_rotation_y, 0.0f));
shader.setMat4f("model", modelm);
renderer.draw(model, shader);
You are storing your rotation as euler angle inside object_rotation.
I advised you to use:
glm::mat4 rotation = glm::eulerAngleYX(object_rotation.y, object_rotation.x); // pitch then yaw
or
glm::mat4 rotation = glm::eulerAngleXY(object_rotation.x, object_rotation.y); // yaw then roll
In your case both should do the job, I advised you in the future to store thoose informations inside your camera (eye, up, center) instead of your object, everything become more simpler.
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));
I've developed 3D application. I want to change pivot between model center and user position. When I toggle changing pivot option, 3D model is moved to some position. My partial source below. Please help me.
glm::vec2 mouse_delta = mouse_move - mouse_click;
key_yaw = rotate_sensitivity * mouse_delta.x;
key_pitch = rotate_sensitivity * mouse_delta.y;
UpdateRotateMatrix();
if (rotate_mode == CCamera::ROT_CENTER)
UpdateModelMatrix();
else if (rotate_mode == CCamera::ROT_CLICKED)
UpdateModelMatrix(false);
////////////////////////////////////////////////////
void CCamera::UpdateModelMatrix(const bool& bCenter)
{
glm::vec3 pivot(0.0f);
if (bCenter)
pivot = local_position; //50.0, 50.0, 50.0
else
pivot = click_position; //1000.0, 1000.0, 1000.0
glm::mat4 rotate = glm::mat4(1.0f);
rotate = glm::translate(glm::mat4(1.0f), pivot)*rotate_matrix;
rotate = rotate * glm::translate(glm::mat4(1.0f), -pivot);
model_matrix = translate_matrix * rotate;
}
void CCamera::UpdateRotateMatrix()
{
glm::quat key_quat = glm::quat(glm::vec3(key_pitch, key_yaw, key_roll));
key_pitch = key_yaw = key_roll = 0;
camera_quat = key_quat * camera_quat;
camera_quat = glm::normalize(camera_quat);
rotate_matrix = glm::mat4_cast(camera_quat);
}
rotation of model center
rotation of some point
The order of you matrices is messed up.
I you want to rotate around a pivot, then you have to:
glm::mat4 trans_to_pivot = glm::translate(glm::mat4(1.0f), -pivot);
glm::mat4 trans_from_pivot = glm::translate(glm::mat4(1.0f), pivot);
glm::mat4 rotate = trans_from_pivot * rotate_matrix * trans_to_pivot;
If you want to scale the model you have to do it first:
glm::mat4 rotate = rotate * scale_matrix;
Note in your example scale_matrix is in between trans_to_pivot and trans_from_pivot, so the first translation is scaled, but the the second translation is not scaled.
Of course pivot has to be a coordinate in scaled model space rather than model space.
I'm trying to rotate an object in a program written with OpenGL.
This object goes around in 3D space.
The angle of rotation on the Y axis (the yaw) is calculated with this:
facingAngle = -atan2(heading.y, heading.x);
…and I add it to the model like this:
glm::mat4 model;
model = glm::translate(model, position);
model = glm::rotate(model, facingAngle, glm::vec3(0.0f, 1.0f, 0.0f));
Then I would like this object to lean towards the direction it's heading to, like a cycle or an aircraft does (rolling).
I have tried countless options to calculate this value, but without any luck to find what I actually want.
The best I get so far, if I do this:
leaningAngle = glm::sqrt(squaredLength(steeringForce)) / gravity;
(The function, squaredLength, does the following: return ( vector.x * vector.x + vector.y * vector.y );)
The main problem with this is that it always leans the object to one given direction (so in half of the cases it leans outwards instead of inwards). However when I would like to modify this value with either *1 or *-1 based on where the object is heading, I get a weird behavior which I suppose is Gimbal lock.
What I would like to have is a simple equation which will give me an angle to roll the object between realistic values (90 and -90 degrees), and the weight of the angle should be calculated based on the current steering force (the sharper the turn, the bigger the leaning angle is).
The final code should be look like this:
glm::mat4 model;
model = glm::translate(model, position);
model = glm::rotate(model, facingAngle, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, leaningAngle, glm::vec3(1.0f, 0.0f, 0.0f));
I've been trying to emulate gluLookAt functionality, but with Quaternions. Each of my game object have a TranslationComponent. This component stores the object's position (glm::vec3), rotation (glm::quat) and scale (glm::vec3). The camera calculates its position each tick doing the following:
// UP = glm::vec3(0,1,0);
//FORWARD = glm::vec3(0,0,1);
cameraPosition = playerPosition - (UP * distanceUP) - (FORWARD * distanceAway);
This position code works as expexted, the camera is place 3 metres behind the player and 1 metre up. Now, the camera's Quaternion is set to the follow:
//Looking at the player's feet
cameraRotation = quatFromToRotation(FORWARD, playerPosition);
The rendering engine now takes these values and generates the ViewMatrix (camera) and the ModelMatrix (player) and then renders the scene. The code looks like this:
glm::mat4 viewTranslationMatrix =
glm::translate(glm::mat4(1.0f), cameraTransform->getPosition());
glm::mat4 viewScaleMatrix =
glm::scale(glm::mat4(1.0f), cameraTransform->getScale());
glm::mat4 viewRotationMatrix =
glm::mat4_cast(cameraTransform->getRotation());
viewMatrix = viewTranslationMatrix * viewRotationMatrix * viewScaleMatrix;
quatFromToRotation(glm::vec3 from, glm::vec3 to) is defined as the following:
glm::quat quatFromToRotation(glm::vec3 from, glm::vec3 to)
{
from = glm::normalize(from); to = glm::normalize(to);
float cosTheta = glm::dot(from, to);
glm::vec3 rotationAxis;
if (cosTheta < -1 + 0.001f)
{
rotationAxis = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), from);
if (glm::length2(rotationAxis) < 0.01f)
rotationAxis = glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), from);
rotationAxis = glm::normalize(rotationAxis);
return glm::angleAxis(180.0f, rotationAxis);
}
rotationAxis = glm::cross(from, to);
float s = sqrt((1.0f + cosTheta) * 2.0f);
float invis = 1.0f / s;
return glm::quat(
s * 0.5f,
rotationAxis.x * invis,
rotationAxis.y * invis,
rotationAxis.z * invis
);
}
What I'm having troubles with is the fact the cameraRotation isn't being set correctly. No matter where the player is, the camera's forward is always (0,0,-1)
Your problem is in the line
//Looking at the player's feet
cameraRotation = quatToFromRotation(FORWARD, playerPosition);
You need to look from the camera position to the player's feet - not from "one meter above the player" (assuming the player is at (0,0,0) when you initially do this). Replace FORWARD with cameraPosition:
cameraRotation = quatToFromRotation(cameraPosition, playerPosition);
EDIT I believe you have an error in your quatToFromRotation function as well. See https://stackoverflow.com/a/11741520/1967396 for a very nice explanation (and some pseudo code) of quaternion rotation.