3
\$\begingroup\$

I am relatively new to OpenGL and 3D environments and am having trouble creating a rotation matrix that will rotate an arrow model so it 'points' in the direction that it is going. I am using GLM as a math library. My current approach is to predict the position the arrow will be at next frame and try to rotate the arrow to face that position.

double nextVelY = velocity.y - (gravity * (((glfwGetTime() + dt) - clock) / 1000.0));
glm::vec3 nextVelocity = velocity;
nextVelocity.y = pos.y - 0.5 > -3 ? nextVelY : velocity.y;

glm::vec3 lookat = glm::vec3((nextVelocity * glm::vec3(20) * glm::vec3(dt)));
glm::vec3 pos2 = glm::vec3(0);

And then try to calculate angles between the current position and the predicted position

model = glm::translate(model, pos);
model = glm::scale(model, glm::vec3(0.05));

float angleX = atan(nextVelocity.y / nextVelocity.z);
float angleY = atan(nextVelocity.x / nextVelocity.z);
float angleZ = atan(nextVelocity.x / nextVelocity.y);

glm::vec3 zAxis = glm::normalize(lookat - pos2);
glm::vec3 xAxis = glm::normalize(glm::cross(up, zAxis));
glm::vec3 yAxis = glm::cross(zAxis, yAxis);

model = glm::rotate(model, angleX, xAxis);
model = glm::rotate(model, angleY, yAxis);
model = glm::rotate(model, angleZ, zAxis);

I'm not at all sure if this is a good way to try and achieve this. I've also tried using glm::lookAt

model = glm::transpose(glm::lookAt(pos2, lookat, glm::vec3(0, 1, 0)));

and various other methods I've found with no success.

\$\endgroup\$
  • \$\begingroup\$ Should simply use quaternions. It can be used with an axis of rotation and an angle. From the looks of it, you are rotating due to gravity right? So you are always rotating along an axis that's at right angle to the direction of velocity. \$\endgroup\$ – ChaoSXDemon Oct 2 '17 at 5:22
  • \$\begingroup\$ @ChaoSXDemon Ahhhh, rotating around an axis perpendicular to to the velocity direction. Why didn't I think of that? :) Thank you that did the trick! \$\endgroup\$ – Salamosaurus Oct 2 '17 at 21:11
2
\$\begingroup\$

The problem of creating a matrix to point somewhere becomes easy to solve once you understand the make-up of a matrix.

Fundamentally, the 4x4 matrix is just a collection of four vectors:

  • The X-Axis
  • The Y-Axis
  • The Z-Axis
  • The Translation (Position)

The identity matrix has x=(1,0,0,0) y=(0,1,0,0), z=(0,0,1,0) and p=(0,0,0,1).

To create a matrix to orient your arrow model, you first need to check how you have modelled your arrow. Is it along the x-axis, the y or the z?

For this discussion I will assume your arrow model points at +x.

The generation of your matrix comes down to generating the four vectors and assembling them into the matrix.

Now, the choice of x-axis is easy: it points to the target for the arrow. Just normalize the target position.

Next, you need to construct two perpendicular axes to this chosen x to come up with an y and z. We will avoid "roll" of the arrow by making the y axis perpendicular to (0,0,1) which is +z, as well as to our chosen x.

This is done with cross product operations.

Recall that for our orthonormal basis, the following is true:

x = y × z
y = z × x
z = x × y

So in pseudo code:

x = targetpos.normalize()
// x now points at target, unit length
y = (0,0,1,0).crossprod( x )
y = y.normalize()
// y is now perpendicular to x, unit length
z = x.crossprod( y )
// z is now perpendicular to both x and y, and unit length
matrix.setRow(0, x)
matrix.setRow(1, y)
matrix.setRow(2, z)
matrix.setRow(3, arrowposition)

Warning: this code will not work if the arrow needs to point straight up to +z, or straight down to -z. In that case, you need to generate the z first, followed by the y-axis.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.