0
\$\begingroup\$

I have successfully set up a billboard shader that works, it can take in a quad and rotate it so it always points toward the screen. I am using this vertex-shader:

void main(){
vec4 tmpPos = (MVP * bufferMatrix * vec4(0.0, 0.0, 0.0, 1.0)) + (MV * vec4(
    vertexPosition.x * 1.0 * bufferMatrix[0][0], 
    vertexPosition.y * 1.0 * bufferMatrix[1][1], 
    vertexPosition.z * 1.0 * bufferMatrix[2][2], 
    0.0)
);

UV = UVOffset + vertexUV * UVScale;
gl_Position = tmpPos;

BufferMatrix is the model-matrix, it is an attribute to support Instance-drawing.

The problem is best explained through pictures:

This is the start position of the camera: start

And this is the position, looking in from 45 degree to the right: same, but 45 degrees to the right

Obviously, as each character is it's own quad, the shader rotates each one around their own center towards the camera. What I in fact want is for them to rotate around a shared center, how would I do this?

What I have been trying to do this far is:

 mat4 translation = mat4(1.0);
    translation = glm::translate(translation, vec3(pos)*1.f * 2.f);
    translation = glm::scale(translation, vec3(scale, 1.f));
    translation = glm::translate(translation, vec3(anchorPoint - pos) / vec3(scale, 1.f));

Where the translation is the bufferMatrix sent to the shader. What I am trying to do is offset the center, but this might not be possible with a single matrix..?

I am interested in a solution that doesn't require CPU calculations each frame, but rather set it up once and then let the shader do the billboard rotation. I realize there's many different solutions, like merging all the quads together, but I would first like to know if the approach with offsetting the center is possible.

If it all seems a bit confusing, it's because I'm a little confused myself.

| improve this question | | | | |
\$\endgroup\$
  • \$\begingroup\$ So pretty much change the center of the transformation-matrix. \$\endgroup\$ – Jacob Kofoed Oct 21 '13 at 15:07
  • \$\begingroup\$ Why not rotate all the smaller quad around a single origin? \$\endgroup\$ – vallentin Oct 21 '13 at 16:00
  • \$\begingroup\$ That is exactly what I want, I want to translate the center of each quad to the same center. In the code given, that point is called "anchorPoint", but how would I do that using only the translationMatrix? \$\endgroup\$ – Jacob Kofoed Oct 21 '13 at 16:08
  • \$\begingroup\$ Ohh, well then how do you store/render the quads using VAO, VBO, Immediate Mode, or? \$\endgroup\$ – vallentin Oct 21 '13 at 16:09
  • \$\begingroup\$ I store the vertex-data in VBOs, but I render the same one multiple times using "GLDrawElementsInstanced". So the vertices are identical for each quad, to make them appear in different locations and have different UV positions etc. I am using instanced attributes. The attribute that change the position is the "bufferMatrix" which is essentially a model-matrix, and the only one that should be changed as the MVP and MV matrix are uniforms. \$\endgroup\$ – Jacob Kofoed Oct 21 '13 at 16:32
3
\$\begingroup\$

I hacked a few lines together and I believe this might get you what I think you want. Basically it all depends on where/when you do the local transformation. You will want to translate the quads to their respective position in clip coordinates, e.g. after the multiplication with the mvp matrix.

vec4 tmpPos = mvp * vec4(0.0, 0.0, 0.0, 1.0) + vec4((local_transform * vec4(vPosition,1.0)).xyz,0.0);

Where the local_transform matrix denotes the gl_InstanceID dependent location of each Quad relative to the rotational center (basically like your bufferMatrix I guess). The rotational center itself would be wherever the model matrix within the mvp matrix would translate the zero vector.

This is what I get with my test application: Transform after mvp

On a side note, I got your result with the following line of code:

vec4 tmpPos = mvp * local_transform * vec4(0.0, 0.0, 0.0, 1.0) + vec4(vPosition,0.0);

And again the result I get in my test: Transformation before mvp

Edit: Fixed two small mistakes. I mixed up clip coordinates with image space, and also carelessly added a 1.0 to the w-component in said clip coords. in my code above. I have corrected both now.

| improve this answer | | | | |
\$\endgroup\$
  • \$\begingroup\$ Like magic, all I had to do was to update the vertex shader with that one line. Thank you so much for your answer, this is a perfect answer! :) I even think I understand what is going on now, shaders are awesome. \$\endgroup\$ – Jacob Kofoed Oct 23 '13 at 15:39
  • \$\begingroup\$ So in order to change the origin of the rotation I would have to feed the shader a vector right? - because right now they will rotate around position (0, 0, 0) or is it possible to change the model-origin with only the local_transform matrix? \$\endgroup\$ – Jacob Kofoed Oct 23 '13 at 16:10
  • \$\begingroup\$ Theoretically you could do that, yes. You could for example swap the vec4(0.0, 0.0, 0.0, 1.0) with another vector which would then be the position of the billboard in the world. In practice, I think this is something which should be done via the model-view-projection matrix, specifically the model part of it should contain a translation to the world position. \$\endgroup\$ – Invor Oct 23 '13 at 17:42

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.