I have seen the post from three years ago asking a somewhat similar question about how to achieve this with glm::lookAt
, but couldn't quite apply it to my game.
I have a camera and player model moving on a curve. This is done by calculating points on the curve and simply moving the player there with glm::translate (identityMatrix, positionCameraIsCurrentlyAt)
, hence I have a current position on the curve and also a nextPosition
.
I now want to rotate the model, using a transformation matrix, but can't seem to get it done. My first idea was to calculate a vector that is currentPosition - nextPosition
to get a vector I should be facing to, I called that targetPoint
. And calculating the vector I am currently facing by simply setting it to (0, 0, 1) for the startup (as you look towards negative z, I guess that's how models are oriented) and updating it to the targetPoint
vector after rotating.
Bot of the vectors are normalized btw.
The code looked like this:
glm::vec3 targetPoint = glm::normalize(position - curveIter->calcCurvePosition(curveProgress));
glm::mat4 rotationMatrix = glm::rotate(modelMatrix, glm::radians(glm::angle(pointingTowards, targetPoint)), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 translationMatrix = glm::translate(modelMatrix, position);
// Test print vectors and angle
std::cout << targetPoint.x << ", " << targetPoint.y << ", " << targetPoint.z << ", " << "pointing towards: " << pointingTowards.x << ", " <<pointingTowards.y << ", " << pointingTowards.z << ", " << glm::angle(glm::normalize(pointingTowards), forward) << std::endl;
pointingTowards = targetPoint;
// Test print vectors and angle
std::cout << targetPoint.x << ", " << targetPoint.y << ", " << targetPoint.z << ", " << "pointing towards: " << pointingTowards.x << ", " << pointingTowards.y << ", " << pointingTowards.z << ", " << glm::angle(glm::normalize(pointingTowards), forward) << std::endl;
return translationMatrix*rotationMatrix;
This didn't really rotate the model at all. I printed the vectors and angle to check them and the results where this:
targetPoint
: (-0.97509, 0, 0.22181)
pointingTowards
: (-0.97509, 0, 0.22181)
angle
: 3.14159
So it seems like they are all way too small. This, I imagine, could be due to the normalization... However, the method says both vectors need to be normalized. The angle
is always Pi which might seem odd but is due to the curve being a circle. This is, obviously, not true for the first angle
which is 2.35469 due to the vectors being targetPoint
(-0.708167, 0, 0.706045) and pointingTowards
: (0, 0, 1) respectively.
Any ideas what I am doing wrong here? Thank you very much!
Assuming you have a position
and a targetPoint
. You can define an upVec
and compute the axis of the rotation matrix by the Cross product as follows:
glm::vec3 upVec(0, 1, 0);
glm::vec3 z_axis = glm::normalize(targetPoint - position);
glm::vec3 x_axis = glm::normalize(glm::cross(upVec, z_axis));
glm::vec3 y_axis = glm::normalize(glm::cross(z_axis, x_axis));
glm::mat4 rotationMatrix(
glm::vec4(x_axis, 0),
glm::vec4(y_axis, 0),
glm::vec4(z_axis, 0),
glm::vec4(0, 0, 0, 1));
Another possibility is to use a Quaternion.
#include <glm/gtx/quaternion.hpp>
Define a rotation from (0, 0, 1) to tragetVec
and convert the quaternion to a rotation matrix:
glm::vec3 tragetVec = glm::normalize(targetPoint - position);
glm::quat rotQuat = glm::rotation(glm::vec3(0, 0, 1), tragetVec);
rotationMatrix = glm::toMat4(rotQuat);