# What are the fundamentals of a Quad Billboarding effect?

I'm taking my first venture in to writing a shader and what I really need to do is create a billboarding effect. A thorough Google search turns up a number of threads on the topic and they always end with

A) Figured it out. Thread closed.

B) Anyone?

C) "long language/system-specific answer without explanation"

Most commonly, people are directed to Riemers which is fine, except his code isn't compatible with XNA 4.0 (what I'm using) and he doesn't explain the shader itself.

Can anyone explain/direct-me-to a language/system agnostic answer of how quad billboarding works?

EDIT: For others so they don't need to dig through the comments: NtscCobalt pointed out that I was attempting to use an orthographic camera when applying the shader. This essentially voided some of the effects of the shader. After changing to a perspective-based cam, the shader worked as it should have.

Here is a simple solution that doesn't require any changes in code to change an object from 3d to billboard. It is probably a hack and might not work in every situation.

Set the constant 'WorldView' to the WorldMatrix*ViewMatrix and 'Projection' to your Projection Matrix. No additional code required. This shader doesn't include lighting but you could use the same lighting code from per-pixel lighting pretty easily. This correctly works with textures by the way.

float4x4 WorldView  : WorldView;
float4x4 Projection : Projection;

texture texture0 : DIFFUSE <
string ResourceName = "default_color.dds";
string UIName =  "Diffuse Texture";
string ResourceType = "2D";
>;

sampler2D colorMap = sampler_state
{
Texture = <texture0>;
MagFilter = Linear;
MinFilter = Anisotropic;
MipFilter = Linear;
MaxAnisotropy = 16;
};

{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};

{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};

{
OUT.Position = mul(IN.Position + float4(WorldView[3].xyz, 0), Projection);
OUT.TextureCoordinate = IN.TextureCoordinate;

return OUT;
}

{
return tex2D(colorMap, IN.TextureCoordinate);
}

{
pass Pass1
{
}
}


Edit: To clarify the way this works is by multiplying the vertices position by the worldview matrix position but ignoring either's rotation and scale. That result is then multiplied by the projection matrix. In short: any object that faces the camera in model space that then uses this shader will face the camera.

• While I appreciate the effort (that did not work for me. I may need to re-visit my camera code) that doesn't answer the question. I was asking for the fundamentals of quad billboarding because I want to understand it, not just copy someone elses code and call it good. – Mike Cluck Oct 28 '11 at 21:25
• @Mike C, Sorry I guess I assumed that the shader spoke for itself. The basic idea here is instead of doing a bunch of math to make the object face the camera we simply ignore the object's orientation and the world matrix's rotation. It sounds strange but works very well for an object that uses a single matrix to determine its location (all relative coordinates stored in vertex data). This billboard uses the shader above without any additional modification/transform. i30.photobucket.com/albums/c308/thentsc/billboard1.png – NtscCobalt Oct 29 '11 at 19:24
• @MikeC, Here is what happens when I take the cogs in the above image and transform them into a billboard (disabled the brick billboard for visibility). i30.photobucket.com/albums/c308/thentsc/billboard2-1.png I got as close in as possible to show how this works with objects that have actual 3d geometry. Again since it doesn't actually rotate the object you can see the object's sides (look at the grass covered cog). The location of the cogs relative to eachother is all wrong because they normally use a relative matrix which this billboarding method doesn't support. – NtscCobalt Oct 29 '11 at 19:27
• That makes sense and seems to work based on the pictures you provided. But for some reason my quads still aren't facing the camera, and in fact are being rendered as pure black squares. Here's a proof-of-concept if you'd care to look pastebin.com/SNqpStF6 – Mike Cluck Oct 29 '11 at 20:14
• @Mike C, It looks like you are doing everything right except for setting the texture. You need a call that either looks like Effect.Parameters["texture0"].SetValue(Texture); or GFX.SetTexture(0, Texture);. Which one depends on how they decided to wrap effects in Managed Direct3D. I'm sure you can find the function call on MSDN. I have to do the same thing in my code depending on if you are using an effect shader (combined vertex and pixel) or if you are using vertex shader + pixel shader. code.google.com/p/cobaltlibrary/source/browse/trunk/Drivers/… – NtscCobalt Oct 29 '11 at 20:27

In the Riemers tutorial, CylBillboardVS is moving each vertex so that the quad faces the camera. It calculates the vectors for how the quad should be facing (upVector points up and sideVector points to the right, perpendicular to the camera direction):

float3 upVector = xAllowedRotDir;
float3 sideVector = cross(eyeVector,upVector);


Then it moves the vertex according to where it is in the texture:

float3 finalPosition = center;
finalPosition += (inTexCoord.x-0.5f)*sideVector;
finalPosition += (1.5f-inTexCoord.y*1.5f)*upVector;


So, if the vertex has UV-coordinates at the top-left of the texture, it'll move to the left (perpendicular to the camera direction) and up along the upVector.

• That makes a certain amount of sense but I guess I'm fundamentally missing something. Whenever I apply that method using that exact shader code then it only blurs my quads, doesn't rotate them. – Mike Cluck Oct 26 '11 at 13:17
• @MikeC without seeing your code we can't say anything about that. COuld you post a small proof of concept? – Roy T. Oct 26 '11 at 16:42
• @RoyT. Sure, I can't believe I forgot to in the first place pastebin.com/eTKVaG2S I made one minor alteration to the shader. The textures are coming from a spritesheet so I just adjusted the way the shader determines which vertex it's moving. – Mike Cluck Oct 27 '11 at 18:21