4
\$\begingroup\$

Say i have something like this:

pos += glm::normalize(target - pos) //PLEASE NOTE: pos is a glm::vec3 and so is target

This makes "pos" translate towards "target", but what if i want to make my object to face "target"?

\$\endgroup\$
6
  • \$\begingroup\$ You find the angle of the vector with atan2, then use that angle to rotate the owner of the 'pos'. \$\endgroup\$
    – Vaillancourt
    Commented Mar 27, 2016 at 17:20
  • \$\begingroup\$ It works fine on rotation of the y axis, but what about the x axis? \$\endgroup\$
    – user68817
    Commented Mar 27, 2016 at 17:22
  • \$\begingroup\$ Oh, you're in 3d? \$\endgroup\$
    – Vaillancourt
    Commented Mar 27, 2016 at 17:22
  • \$\begingroup\$ Indeed it is so. \$\endgroup\$
    – user68817
    Commented Mar 27, 2016 at 17:23
  • \$\begingroup\$ Ok, what I had in my comment was good in 2d. It's a bit more complex in 3d because there is an 'up' vector that has to be taken into consideration. \$\endgroup\$
    – Vaillancourt
    Commented Mar 27, 2016 at 17:25

3 Answers 3

4
\$\begingroup\$

Making a model always face a point is trickier in 3d than it is in 2d: the added dimension makes one wonder "what about the UP?".

This here assumes that you want your model to stay vertical as much as possible, and it uses the following coordinate system.

// z+    y+
// |    /
// |   /
// |  /
// | /
// |/ 
//  ¯¯¯¯¯¯¯¯¯¯¯¯ x+

This also assumes that the 'front' vector of your model is in x+ and that the 'side' vector is y+ (and of course, 'up' is z+).

glm::vec3 dirglm( dir.x(), dir.y(), dir.z() ); // dir is normalized

// find the angle about world-frame-z-axis
double angle = std::atan2( dir.y(), dir.x() );

// Make the rotation matrix around the vertical (z) axis, adjusts the 'yaw'
glm::mat4 glmrotXY = glm::rotate( angle, glm::tvec3<double>( 0.0, 0.0, 1.0 ) );

// Find the angle with the xy with plane (0, 0, 1); the - there is because we want to 
// 'compensate' for that angle (a 'counter-angle')
double angleZ = -std::asin( (dir).z() );

// Make the matrix for that, assuming that Y is your 'side' vector; makes the model 'pitch'
glm::mat4 glmrotZ = glm::rotate( angleZ, glm::tvec3<double>( 0.0, 1.0, 0.0 ) );

object->setRotationMatrix( glmrotXY * glmrotZ );

This will cause a behaviour similar to the one of a camera in a 3rd person view kind of game (I'm thinking MMORPG style). It has the caveat that you can't have 'pos' directly above or below.

\$\endgroup\$
2
\$\begingroup\$

You just need the standard lookat function.

#include <glm/gtc/matrix_transform.hpp>

glm::vec3 const up(0.f, 0.f, 1.f);
object->setRotationMatrix(glm::lookAt(pos, target, up));

That’s all! Replace (0.f, 0.f, 1.f) with whatever you want your “up” vector to be.

\$\endgroup\$
0
\$\begingroup\$

If direction and up vectors are collinear, then you're in trouble. I think direction by itself is not enough to describe orientation in 3D space. So the answer is no, you can't just convert direction into rotation matrix.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ "you can't just convert direction into a rotation matrix" somewhat contradicts the two other answers that show how you can indeed do that, with a little care in selecting an appropriate up vector. There isn't a universal or perfect way to do it due to the hairy ball theorem, but there are ways that are "good enough" for our needs in games. \$\endgroup\$
    – DMGregory
    Commented Jan 7, 2019 at 11:52

You must log in to answer this question.