2
\$\begingroup\$

I am trying to rotate a sprite so it is always facing a 3D camera.

Object

GLfloat vertexData[] = {
    //  X     Y     Z       U     V
    0.0f, 0.8f, 0.0f,   0.5f, 1.0f,
    -0.8f,-0.8f, 0.0f,   0.0f, 0.0f,
     0.8f,-0.8f, 0.0f,   1.0f, 0.0f,
};

Per frame transform

glm::mat4 newTransform = glm::lookAt(glm::vec3(0), gCamera.position(), gCamera.up());
shaders->setUniform("camera", gCamera.matrix());
shaders->setUniform("model", newTransform);

In the vertex shader:

gl_Position = camera * model * vec4(vert, 1);

The object will track the camera if I move the camera up or down, but if I move the camera left/right (spin the camera around the object's y axis), it will rotate in the other direction so I end up seeing its front twice and its back twice as I rotate around it 360.

If I use -gCamera.up() instead, it would track the camera side to side, but spin the opposite direction when I move the camera up/down.

What am I doing wrong?

\$\endgroup\$
  • 1
    \$\begingroup\$ Possible duplicate: Orienting a model to face a target \$\endgroup\$ – MichaelHouse Jun 28 '13 at 3:32
  • \$\begingroup\$ Thanks, I can get my object to face the camera with that solution, but the orientation does not align with the camera. Ideally, I just want the location of the object in camera space and render a 2D sprite using a quad over it. \$\endgroup\$ – omikun Jun 28 '13 at 16:46
  • \$\begingroup\$ It sounds like you're actually more interested in creating a billboard? \$\endgroup\$ – MichaelHouse Jun 28 '13 at 16:51
  • \$\begingroup\$ Yes, but I haven't found any modern opengl tutorial on constructing a billboard. Do you know of any? \$\endgroup\$ – omikun Jun 29 '13 at 2:51
  • \$\begingroup\$ Yes, gamedev.stackexchange.com/questions/35946/… \$\endgroup\$ – MichaelHouse Jun 29 '13 at 2:56
3
\$\begingroup\$

I'd like to share an alternative solution based on the assumption that you have access to the view matrix. It has the advantage to make the billboard stay exactly perpendicular to the view vector instead of just orienting the billboard towards the camera. See it neatly explained here: https://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/

You don't have to compute anything, just use the transpose of the top 3x3 section of the view matrix and the billboard position vector:

                     V11 V21 V31 P.x
billboardTransform = V12 V22 V32 P.y
                     V13 V23 V33 P.z
                      0   0   0   1

Where P is the world position of the billboard object and V is the view matrix defined as:

|V11 V12 V13 V14|
|V21 V22 V23 V24|
|V31 V32 V33 V34|
|V41 V42 V43 V44|

Note: Indexing is done using mathematical notation. Therefore, don't forget to take into consideration the memory layout of your data (row-major / column-major).

\$\endgroup\$
  • \$\begingroup\$ brilliant, this answer worked when nothing else did. A++ \$\endgroup\$ – Jeff Strom Sep 4 '19 at 1:42
0
\$\begingroup\$

glm::lookat was not what I wanted after all. Found the answer here

For completeness sake, the code is reproduced below (I changed the translate line to vec4(position, 1), otherwise it doesn't translate):

mat4 billboard(vec3 position, vec3 cameraPos, vec3 cameraUp) {
vec3 look = normalize(cameraPos - position);
vec3 right = cross(cameraUp, look);
vec3 up2 = cross(look, right);
mat4 transform;
transform[0] = vec4(right, 0);
transform[1] = vec4(up2, 0);
transform[2] = vec4(look, 0);
// Uncomment this line to translate the position as well
// (without it, it's just a rotation)
//transform[3] = vec4(position, 1);
return transform;
}

The reason why I don't want to manipulate each vertex of the billboard is because I plan on using more complicated 2d geometry in the future.

\$\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.