0
$\begingroup$

I'm trying to create a vertex shader that billboards a quad. Most resources online show the code to be some variation of the following

gl_Position = project * (view * model * billbrd_pos + vec4(position.xy, 0, 0));

So I tried doing something similar in HLSL after doing some research

static const float3 BILLBOARD[] = {
    float3(-1, 1, 0),   // 0
    float3(1, 1, 0),    // 1
    float3(-1, -1, 0),  // 2
    float3(-1, -1, 0),  // 3
    float3(1, 1, 0),    // 4
    float3(1, -1, 0),  // 5
};

input.position.w = 1.0f;

float3 bpos = BILLBOARD[vertexID];

matrix WV = mul(worldMatrix, viewMatrix);

output.position = mul(projectionMatrix,
    mul(WV, float4(bpos, 1.0f))
    + float4(input.position.x, input.position.y, 0.0f, 0.0f)
    * float4(1.0f, 1.0f, 1.0f, 1.0f));

But this doesn't work as the quad disappears from the screen. How can I achieve billboarding in a vertex shader in HLSL?

Edit

As per @pmw1234 's answer I changed the upper 3x3 section of the view matrix to an identity matrix as shown below, the billboard now works correctly.

matrix viewIdentity = viewMatrix;
viewIdentity[0][0] = 1;
viewIdentity[0][1] = 0;
viewIdentity[0][2] = 0;

viewIdentity[1][0] = 0;
viewIdentity[1][1] = 1;
viewIdentity[1][2] = 0;

viewIdentity[2][0] = 0;
viewIdentity[2][1] = 0;
viewIdentity[2][2] = 1;

float4 Vpos = mul(bpos, worldMatrix);
Vpos = mul(Vpos, viewIdentity);
$\endgroup$

1 Answer 1

1
$\begingroup$

I did a little code cleaning and came up with this:

static const float3 BILLBOARD[] = {
    float3(-1, 1, 0),   // 0
    float3(1, 1, 0),    // 1
    float3(-1, -1, 0),  // 2
    float3(-1, -1, 0),  // 3
    float3(1, 1, 0),    // 4
    float3(1, -1, 0),  // 5
};

float4 bpos = float4( input.position.xy, 0, 0);
float4 bbOffset = float4(BILLBOARD[vertexID],0);

matrix WV = mul(worldMatrix, viewMatrix);
float4 Vpos = mul(WV, bpos);
float4 OffsetPos = Vpos + bbOffset;
float4 projected = mul( projectionMatrix, OffsetPos);

output.position = projected;

The code you posted is using the billboard offset to compute the Vpos, but what you really want is to use the input.position (the billboard position) to compute the camera space position. This became clear after doing the code clean up. I'm not sure if it will "fix" the code, but it should get you a step closer.


There are a number of ways to compute billboard orientation. One trick is to simply overwrite the upper 3x3 portion of the view matrix with the identity matrix before using it to compute the vertex.

Another is to compute a forward vector ie

n = normalize(camera_pos - bb_pos);

then, a right vector ie

d = normalize(cross(n, camera_down);

and finally a down/up vector

r = cross( n, d);

These can be used to rotate the bb position with matrix multiplication.

$\endgroup$
3
  • $\begingroup$ Thanks for your answer, this code alone doesn't rotate the quad towards the camera like one would expect for a billboard, it looks like the bbOffset still needs to be modified by another parameter to complete the effect... see my edit if you're interested $\endgroup$
    – H3XXX
    Commented Nov 11, 2021 at 18:32
  • 1
    $\begingroup$ I added a bit to my answer hopefully this will get you a little closer to what you want. $\endgroup$
    – pmw1234
    Commented Nov 12, 2021 at 11:55
  • $\begingroup$ The view/identity matrix trick worked perfectly. Thanks! $\endgroup$
    – H3XXX
    Commented Nov 12, 2021 at 18:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.