Started by Jan 23 2012 11:47 PM

,
3 replies to this topic

Posted 23 January 2012 - 11:47 PM

I been long searching hard for the right code to do proper billboarding regardless of camera angle used. I tried a few samples but found that they either don't seem to work right in certain camera angles, or only billboard for me when I translate the camera around the world with camera angles not having any affect on them billboardwise, cause when I rotate the camera it still rotates the polygon when its not suppose to, Then finally I found some useful code over on this site http://www.mvps.org/..._billboards.htm . This works flawlessly regardless of camera angle and position. However there is just one problem. I do not like the fact I'm stuck having to work with a diamond shaped polygon. I tried making it just a regular square but everything I tried fails. Even tried rotating the poly itself by its Z axis 45 degrees but then I end up losing the billboard effect. Is there anyway I can use this technique and work with regular squares / rectangles rather than the "diamond" that microsoft was using? Thanks in advance.

Posted 24 January 2012 - 02:29 AM

I found a simple solution to this. Here is how I build the 4 vertices of each quad when I fill an array of particles:

See how I am encoding the distance from the centre of the billboard into the X and Y of its normal. If I came up with my own vertex format this wouldnt be necessary, and there are other ways.

My shader is very simple; only the vertex shader has anything notable in it:

Now, there are other ways to do this; you could use the texcoords to achieve the same effect, or instead you could use a single index which picks from an array within a shader, but I implemented this in a hurry.

#region setting up verts int si = i * 4; float age = pData[i + offset].age; int z = nDrawn & 1; float rev = ( z == 1 ) ? -1f : 1f; Matrix rotm = Matrix.CreateRotationZ(age * 5f * rev); // point sprite style rendering - use the first 2 points of the normal to encode the coordinates, // relative to the Position, of each of the 4 verts // use the 3rd component of the normal to encode the age, for shaders to apply their own age dependent logic StaticBuffer[si].Position = pData[i + offset].pos; StaticBuffer[si].TextureCoordinate.X = 0; StaticBuffer[si].TextureCoordinate.Y = 0; StaticBuffer[si].Normal.X = -0.5f; StaticBuffer[si].Normal.Y = -0.5f; StaticBuffer[si].Normal.Z = age; si++; StaticBuffer[si].Position = pData[i + offset].pos; StaticBuffer[si].TextureCoordinate.X = 1; StaticBuffer[si].TextureCoordinate.Y = 0; StaticBuffer[si].Normal.X = 0.5f; StaticBuffer[si].Normal.Y = -0.5f; StaticBuffer[si].Normal.Z = age; si++; StaticBuffer[si].Position = pData[i + offset].pos; StaticBuffer[si].TextureCoordinate.X = 1; StaticBuffer[si].TextureCoordinate.Y = 1; StaticBuffer[si].Normal.X = 0.5f; StaticBuffer[si].Normal.Y = 0.5f; StaticBuffer[si].Normal.Z = age; si++; StaticBuffer[si].Position = pData[i + offset].pos; StaticBuffer[si].TextureCoordinate.X = 0; StaticBuffer[si].TextureCoordinate.Y = 1; StaticBuffer[si].Normal.X = -0.5f; StaticBuffer[si].Normal.Y = 0.5f; StaticBuffer[si].Normal.Z = age; #endregion

See how I am encoding the distance from the centre of the billboard into the X and Y of its normal. If I came up with my own vertex format this wouldnt be necessary, and there are other ways.

My shader is very simple; only the vertex shader has anything notable in it:

output.Position = mul( mul( mul(input.Position, matWorld) , matView), matProjection) + float4(input.Normal.xy * input.Normal.z, 0, 0);

Now, there are other ways to do this; you could use the texcoords to achieve the same effect, or instead you could use a single index which picks from an array within a shader, but I implemented this in a hurry.

Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!

Posted 24 January 2012 - 03:16 AM

Inverse of camera's rotation matrix (3x3 part) will negate camera's rotation effect and your quad will always face camera.

Setup generic quad:

Then get inverse of view:

Then in shader it's simple: OutPosition = QuadVertex.Position * ViewInverse * View * Proj;

I used instancing, so for me it was OutPosition = (QuadVertex.Position * ViewInverse + QuadInstancedPosition) * View * Proj;

Setup generic quad:

struct QuadPoint { D3DXVECTOR3 xyz; D3DXVECTOR2 tex; } points[4]; points[0].xyz = D3DXVECTOR3(-0.05, -0.05, 0); points[0].tex = D3DXVECTOR2(0, 0); points[1].xyz = D3DXVECTOR3(-0.05, 0.05, 0); points[1].tex = D3DXVECTOR2(0, 1); points[2].xyz = D3DXVECTOR3(0.05, -0.05, 0); points[2].tex = D3DXVECTOR2(1, 0); points[3].xyz = D3DXVECTOR3(0.05, 0.05, 0); points[3].tex = D3DXVECTOR2(1, 1);You can duplicate this quad into many quads and then add positions of particles, but personally I used this quad as base mesh and instanced particle positions.

Then get inverse of view:

ViewInverse = *camera.GetViewMatrix(); D3DXMatrixInverse(&ViewInverse, 0, &ViewInverse); ViewInverse._41 = 0; ViewInverse._42 = 0; ViewInverse._43 = 0;Last 3 lines remove camera's translation part.

Then in shader it's simple: OutPosition = QuadVertex.Position * ViewInverse * View * Proj;

I used instancing, so for me it was OutPosition = (QuadVertex.Position * ViewInverse + QuadInstancedPosition) * View * Proj;

Posted 25 January 2012 - 12:39 AM

I managed to pull it off. And I think the technique I was looking for is called View Oriented Billboarding. I ran into this site here: http://www.toymaker...._faq.html#D3D10 but it was missing something big cause it seemed incomplete. It needed to multiply the matrix "result" by the vertices you have for your polgon.Here is the solution to my problem:

You are now no longer limited to "diamonds" as microsoft had and can make the shape pretty much anything you want whether its a triangle, rectangle, square, etc. and it'll always face the user. I can't believe that after a ton of samples I attempted, some of which are horrible, didn't even do it right. Out of curiosity I heard there are many other Billboarding techniques out there such as these in this sitehttp://www.flipcode....eringi_2E.shtml along with spherical billboarding and cylindrical billboarding. Where can I find how to these different techniques with source code examples? Would be interesting to learn how.

Private Sub D3DXMatrixMultiplyByVertex(VOut As D3DVECTOR, M As D3DMATRIX, V As D3DVECTOR) VOut.X = (V.X * M.m11) + (V.Y * M.m21) + (V.Z * M.m31) VOut.Y = (V.X * M.m12) + (V.Y * M.m22) + (V.Z * M.m32) VOut.Z = (V.X * M.m13) + (V.Y * M.m23) + (V.Z * M.m33) End Sub Private Sub Draw_Billboard_Polygon() Dim Vertex(3) As D3DVECTOR Dim Camera_Inverse As D3DMATRIX Dim Result As D3DMATRIX Dim Temp As D3DMATRIX Dim Billboard_Vertex(3) As D3DVECTOR Device.GetTransform D3DTS_VIEW, Camera_Matrix D3DXMatrixInverse Camera_Inverse, 0, Camera_Matrix Camera_Inverse.m41 = 0 Camera_Inverse.m42 = 0 Camera_Inverse.m43 = 0 D3DXMatrixIdentity Temp D3DXMatrixMultiply Result, Temp, Camera_Inverse Result.m41 = Position.X Result.m42 = Position.Y Result.m43 = Position.Z Device.SetTransform D3DTS_WORLD, World_Matrix Vertex(0).X = -50: Vertex(0).Y = 50: Vertex(0).Z = 0 Vertex(1).X = 50: Vertex(1).Y = 50: Vertex(1).Z = 0 Vertex(2).X = -50: Vertex(2).Y = -50: Vertex(2).Z = 0 Vertex(3).X = 50: Vertex(3).Y = -50: Vertex(3).Z = 0 D3DXMatrixMultiplyByVertex Billboard_Vertex(0), Result, Vertex(0) D3DXMatrixMultiplyByVertex Billboard_Vertex(1), Result, Vertex(1) D3DXMatrixMultiplyByVertex Billboard_Vertex(2), Result, Vertex(2) D3DXMatrixMultiplyByVertex Billboard_Vertex(3), Result, Vertex(3) Vertex_List(0) = Create_Custom_Vertex(Billboard_Vertex(0).X, Billboard_Vertex(0).Y, Billboard_Vertex(0).Z, D3DColorRGBA(255, 255, 255, 255), 0, 0) Vertex_List(1) = Create_Custom_Vertex(Billboard_Vertex(1).X, Billboard_Vertex(1).Y, Billboard_Vertex(1).Z, D3DColorRGBA(255, 255, 255, 255), 1, 0) Vertex_List(2) = Create_Custom_Vertex(Billboard_Vertex(2).X, Billboard_Vertex(2).Y, Billboard_Vertex(2).Z, D3DColorRGBA(255, 255, 255, 255), 0, 1) Vertex_List(3) = Create_Custom_Vertex(Billboard_Vertex(3).X, Billboard_Vertex(3).Y, Billboard_Vertex(3).Z, D3DColorRGBA(255, 255, 255, 255), 1, 1) Device.SetVertexShader CUSTOM_VERTEX_FORMAT Device.SetTexture 0, Texture Device.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 2, Vertex_List(0), Len(Vertex_List(0)) End Sub

You are now no longer limited to "diamonds" as microsoft had and can make the shape pretty much anything you want whether its a triangle, rectangle, square, etc. and it'll always face the user. I can't believe that after a ton of samples I attempted, some of which are horrible, didn't even do it right. Out of curiosity I heard there are many other Billboarding techniques out there such as these in this sitehttp://www.flipcode....eringi_2E.shtml along with spherical billboarding and cylindrical billboarding. Where can I find how to these different techniques with source code examples? Would be interesting to learn how.