1

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?

Community
  • 1
  • 1
Carles Araguz
  • 1,157
  • 1
  • 17
  • 37
  • What I would do is scale the model matrix by `(view*center).z` so the size on screen is always the same. For the actual orientation matrix, it should be the transpose of the view matrix (so they both cancel out). – pleluron Jan 20 '17 at 16:00

1 Answers1

4
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.

pleluron
  • 733
  • 4
  • 12
  • 1
    Thanks that solved the problem. I wonder, however, what's the underlying math of that operation. Why the distance to the camera (which is what I think the `dist` variable represents) has to be multiplied by the ___x___ and ___y___ coordinates of each vertex? – Carles Araguz Jan 23 '17 at 15:44
  • 2
    Perspective makes objects look smaller at a distance, so you just have to scale them up, relative to that distance. Also it could be `vec4(position.xyz*dist,0)`, as you said you have a 3D object to render. – pleluron Jan 23 '17 at 19:38