Search code examples
openglmatrixrotationglslshader

How to remove rotation from model-view matrix so that object always faces camera?


I'm trying to make sprites always face the camera, and I have understood that it's possible to remove the rotation from the model-view matrix, like this:

(https://stackoverflow.com/a/5487981/12817501)

Original:

| xx xy xz xw |
| yx yy yz yw |
| zx zy zz zw |
| wx wy wz ww |

Rotation removed:

| 1  0  0  xw |
| 0  1  0  yw |
| 0  0  1  zw |
| wx wy wz ww | 

My vertex shader:

#version 450 core

layout (location = 0) in vec3 mesh;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 worldPos;
layout (location = 3) in mat4 model;

uniform mat4 proj, view;

out Data
{
    vec2 texCoord;
} outData;

void main()
{
    outData.texCoord = texCoord;

    // Remove rotation so that it always faces the camera

    mat4 mv = view * model;

    mv[0][0] = 1;
    mv[0][1] = 0;
    mv[0][2] = 0;
    mv[1][0] = 0;
    mv[1][1] = 1;
    mv[1][2] = 0;
    mv[2][0] = 0;
    mv[2][1] = 0;
    mv[2][2] = 1;

    gl_Position = proj * mv * vec4(mesh + worldPos, 1);
}

The rotation does in fact get removed, but all the sprites are still inaccurately affected by camera orientation. If I do not move the camera the sprites are in the their correct positions, but if I move it they "fly away".

What am I doing wrong?

EDIT: if I turn the camera 90 degrees to the left they are in their correct positions.


Solution

  • Your suggestion is not correct. The view matrix defines the look at the scene. If you cancel the rotation component of the view matrix, you change the line of sight.
    You have to rotate the model in the opposite direction of the view, to keep it facing the xy plane of the view spaces.
    The opposite rotation can be get by the computing the inverse matrix of the view matrix and nullifying the translation component. That means you have to compute the inverse matrix of the upper left 3x3 of the view matrix:

    mat3 invViewRot = inverse(mat3(view));
    vec3 pos        = worldPos + invViewRot * mesh;
    
    gl_Position = proj * view * model * vec4(pos, 1.0);