Billboard with a pivot
Hello!
I am having some terrible troubles with mathematics behind 'billboarding'. Actually, it's not just a simple case of standard billboards. The problem is rather tricky. This is very important for me and I would be grateful if you could help.
Sometimes you want to have a billboard with a 'pivot point' - that is, a quad which is always parralel to the screen's surface (XY plane of the camera) and moves around a static point (the pivot). For instance, you can think of a 3D tree mesh with leaves represented as billboards which are attached to branches of the tree.
Here is where problems begin. The first thing is that I don't know how to make a billboard which would rotate about a given point (I believe the difficulty comes from my beginners mathematics). The second thing is that the billboarding *MUST* be implemented on a vertex shader (since I don't have an acess to the engine's code).
Perhaps some pictures may help :
... a tree with leaves attached to the branches.
... a billboard from top (note that leaves rotate about the pivot).
Now, to be more specific about what I can do. Every single leaf is represented by a simple mesh-object (quad). Thus, every leaf has its own modelview matrix.
The vertex shader (GLSL) as an input gets some pre-declared attributes (vertex position in local coordinates, modelview, inverse of the modelview etc...). Plus, I have no possibility to pass any custom uniform parameters. :(
Of course, we can assume that vertices of the leaf-mesh are arbitrarily prepared by the modeller (say, some extra info stored in texture coordinates). The pivot point can be stored as a (0,0,0) in a local leaf-coordinates (but fell free to change it if you don't think it's a good idea). I hope it makes sense... and I hope it's possible to do in a shader.
I'd be thankful if you could give me some suggestion/advice/links/tutorials/books titles or anything! I've been sitting three days on this one and I still can't figure that out.
Thanks in advance
Making the whole tree as the billboard instead of just leaves won't give the same result at all.
Now, to the problem, you simply need sprites. Googling for "sprites OpenGL" (or DirectX, but in this case, the ID3DXSprite interface will do the job) will give you pretty good results.
I use the following approach. I build a vertex and and index buffer. For each vertex, I use the following structure
Each quad is composed of 4 vertices, and 6 indices. Now, for each 4 vertices, I store the PIVOT point in "position". In "uv", I store the correct uv, and in "size" I store the width / height of the quad in WORLD coordinates. Well, it's not really the width / height. For example, for the upper left vertex, the size will be {-width / 2, height / 2} and for the upper right {width / 2, height / 2}. It's
Now, I use the following shader :
Ok, now the explanation. When going into camera space, the X and Y axis are aligned to the screen, and the dimension are still in world space ! That makes it a lot easier to handle your quads : you have the sizes in world space, and you can move the vertices easily in a plane aligned to the screen.
That's a really simple shader, it's easy to work with. The only drawback is that you have 2 matrix multiplications. But on the other hand, you very few additional instructions and it's very easy to create the vertices for this shader.
Hope that helps ^^
Now, to the problem, you simply need sprites. Googling for "sprites OpenGL" (or DirectX, but in this case, the ID3DXSprite interface will do the job) will give you pretty good results.
I use the following approach. I build a vertex and and index buffer. For each vertex, I use the following structure
struc SVertex{ D3DXVECTOR3 position; D3DXVECTOR2 uv; D3DXVECTOR2 size;};
Each quad is composed of 4 vertices, and 6 indices. Now, for each 4 vertices, I store the PIVOT point in "position". In "uv", I store the correct uv, and in "size" I store the width / height of the quad in WORLD coordinates. Well, it's not really the width / height. For example, for the upper left vertex, the size will be {-width / 2, height / 2} and for the upper right {width / 2, height / 2}. It's
Now, I use the following shader :
void BillboardVS(in float3 iPosition : POSITION, in float2 iTexCoord0 : TEXCOORD0, in float2 iSize : TEXCOORD1, out float4 oPosition : POSITION, out float2 oTexCoord0 : TEXCOORD0 ){ // transform the vertex in camera space iPosition = mul(iPosition, g_mWorldView); // decal the vertex to form the quad iPosition.x += iSize.x; iPosition.y += iSize.y; // finally transform the vertex in screen space oPosition = mul(iPosition, g_mProjection); // copy the tex coord for the pixel shader oTexCoord0 = iTexCoord0;}
Ok, now the explanation. When going into camera space, the X and Y axis are aligned to the screen, and the dimension are still in world space ! That makes it a lot easier to handle your quads : you have the sizes in world space, and you can move the vertices easily in a plane aligned to the screen.
That's a really simple shader, it's easy to work with. The only drawback is that you have 2 matrix multiplications. But on the other hand, you very few additional instructions and it's very easy to create the vertices for this shader.
Hope that helps ^^
Hi, guys! Great thanks for your post, piac. It's very explanatory! :)
Anyway, I would like to make myself sure that I understand your idea completly. Firstly, what do you mean by storing the pivot point in 'position'? For me, a pivot is a fixed point that the billboard 'rotates' about. Storing the pivot in a vertex position (in local coordinates - as input in the vertex shader) would mean that every vertex of the quad would have the same position (since there is only one pivot point)!
Perhaps there I missed something important. I'd be glad if you could make this clear for me.
Thank you for your help
Anyway, I would like to make myself sure that I understand your idea completly. Firstly, what do you mean by storing the pivot point in 'position'? For me, a pivot is a fixed point that the billboard 'rotates' about. Storing the pivot in a vertex position (in local coordinates - as input in the vertex shader) would mean that every vertex of the quad would have the same position (since there is only one pivot point)!
Perhaps there I missed something important. I'd be glad if you could make this clear for me.
Thank you for your help
Hi,
Yes, the 4 vertices store the same position. But the 2 following lines
are here to create the quad. For example, if you want a quad centered on <5 5 5> and with a width / height of 3, then you would have the following structure :
So, for each vertex, the position is transformed into camera space, so that the X and Y axis become screen aligned, BUT your units are still world units (e.g., if in world space, 1 unit == 1 meter, then in camera space, 1 unit still == 1 meter, on the contrary of screen space where 1 unit == 1 pixel)
And the lines
will then "kind of" extrude your quad : the first vertex will be move upper left, the second, down left, the third upper right, and the last one down right.
I don't know how to explain better, I'm not really good at explaining things in english. But I hope this example clarified your ideas ^^
Yes, the 4 vertices store the same position. But the 2 following lines
iPosition.x += iSize.x; iPosition.y += iSize.y;
are here to create the quad. For example, if you want a quad centered on <5 5 5> and with a width / height of 3, then you would have the following structure :
SVertex vertices[] = { {5.0f, 5.0f, 5.0f, 0.0f, 0.0f, -2.5f, 2.5f}, {5.0f, 5.0f, 5.0f, 0.0f, 1.0f, -2.5f, -2.5f}, {5.0f, 5.0f, 5.0f, 1.0f, 0.0f, 2.5f, 2.5f}, {5.0f, 5.0f, 5.0f, 1.0f, 1.0f, 2.5f, -2.5f} };
So, for each vertex, the position is transformed into camera space, so that the X and Y axis become screen aligned, BUT your units are still world units (e.g., if in world space, 1 unit == 1 meter, then in camera space, 1 unit still == 1 meter, on the contrary of screen space where 1 unit == 1 pixel)
And the lines
iPosition.x += iSize.x; iPosition.y += iSize.y;
will then "kind of" extrude your quad : the first vertex will be move upper left, the second, down left, the third upper right, and the last one down right.
I don't know how to explain better, I'm not really good at explaining things in english. But I hope this example clarified your ideas ^^
You've explained it perfectly, paic. I wish there where more people on the forum who can give such a clear explanations. :)
OK, I need to consult the artist and I am right into your solution!
Thanks
OK, I need to consult the artist and I am right into your solution!
Thanks
Quote:Original post by clapton
You've explained it perfectly, paic. I wish there where more people on the forum who can give such a clear explanations. :)
OK, I need to consult the artist and I am right into your solution!
Thanks
Hi Clapton,
The way I do my billboards is as such.
Create a vertex buffer containing my texture coordinates which I know will never change: (0,0), (1,0), (0, 1), (1,1)
Create another vertex buffer containing positions and radii.
Then (in DirectX at least) you can use the stream frequency function. Set it to divide by 4 on the vertex buffer containing the positions and radii. Set it to modulo by 4 on the vertex buffer containing the texture coordinates. This will have the same effect but less than 1/4 the size of data.
In my vertex shader I simply use the texture coordinates to offset the corners of my quad by converting the range of the UVs from [0,1] to [-1,1].
Cheers,
Tom.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement