Search code examples
opengl3dshadervertex-shadergeometry-shader

How to transform vertices in vertex shader to get a 3D billboard


I'm trying to implement vertex shader code to achieve the "billboard" behaviour on a given vertex mesh. What I want is to define the mesh normally (like a 3D object) and then have it always facing the camera. I also need it to always have the same size (screen-wise). This two "effects" should happen:

Billboard in which the size is preserved despite the camera being far away Billboard in which the rotation is fixed despite rotating the camera

The only difference in my case is that instead of a 2-D bar, I want to have a 3D-object.

To do so, I'm trying to follow the alternative 3 in this tutorial (the same where the images are taken from), but I can't figure out many of the assumptions they made (probably due to my lack of experience in graphics and OpenGL).

My shader applies the common transformation stack to vertices, i.e.:

gl_Position = project * view * model * position;

Where position is the input attribute with the vertex location in world-space. I want to be able to apply model-transformations (such as translation, scale and rotation) to modify the orientation of the object with respect to the camera. I understand the concepts explained in the tutorial but I can't seem to understand ho to apply them in my case.

What I've tried is the following (extracted from this answer, and similar to the tutorial):

uniform vec4 billbrd_pos;
...
gl_Position = project * (view * model * billbrd_pos + vec4(position.xy, 0, 0));

But what I get is a shape the size of which is bigger when is closer to the camera, and smaller otherwise. Did I forgot something?

Is is possible to do this in the vertex shader?


Solution

  • uniform vec4 billbrd_pos;
    ...
    vec4 view_pos = view * model * billbrd_pos;
    float dist = -view_pos.z;
    gl_Position = project * (view_pos + vec4(position.xy*dist,0,0));
    

    That way the fragment depths are still correct (at billbrd_pos depth) and you don't have to keep track of the screen's aspect ratio (as the linked tutorial does). It's dependent on the projection matrix though.