Sign in to follow this  
M4573R

Billboarded sprite transform

Recommended Posts

I'm trying to make my particles face the camera, but I'm having some troubles. Is there a way to do the transform without each particle's world matrix needing to have a rotation in it? I don't want to have to go out and grab the camera specifics in order to construct the world matrix. Can you have just a modified view matrix for this?

Share this post


Link to post
Share on other sites
You need the full featured view matrix to compute the position (in view space) of the particles correctly, but you can ignore it totally when computing the rotation. Hence, you don't need a local-to-global matrix for each particle, but a local-to-global matrix for the particle system as an entirety, and just a position for each particle.

Share this post


Link to post
Share on other sites
Quote:
Original post by haegarr
You need the full featured view matrix to compute the position (in view space) of the particles correctly, but you can ignore it totally when computing the rotation. Hence, you don't need a local-to-global matrix for each particle, but a local-to-global matrix for the particle system as an entirety, and just a position for each particle.


Well the way I have it set up now is that my particle system is setting a world transform matrix for each particle and rendering it. I'm trying to keep it generic to the way I'm rendering everything else. My particle system doesn't know where the camera is. So I'm trying to do all the billboard calculations in the renderer before I tell my objects to set a world matrix and draw.

Share this post


Link to post
Share on other sites
Quote:
Original post by M4573R
Well the way I have it set up now is that my particle system is setting a world transform for each particle and rendering it. I'm trying to keep it generic to the way I'm rendering everything else.

A local-to-global matrix has ever also a rotation part, even if it is the identity rotation. The rendering pipeline from local to view space for a point p is (using column vectors)
V * M * p
where V denotes the view matrix and M the model (i.e. local-to-global) matrix. Neglecting scaling, then the composition from translations and rotations looks like
TV * RV * TM * RM * p
what you want to decompose, so that
= T' * R' * p
where R' should be I.

Going to affine space, the requirement above looks like
tV + RV * ( RM * p + tM ) == tV + RV * RM * p + RV * tM
= t' + R' * p
so that a coefficient comparison shows that
R' = RV * RM
and hence, due to R' should be identity,
RM = RV-1

So there is an influence of the view onto the rotation matrix of the particle. You cannot avoid the rotation part in the matrix, and you cannot avoid the view rotation having an impact.

So AFAIK you have 2 choices: Either compute the position of the particle as usual, and perform the remaining stuff directly in view space (as I suggested above), or else incorporate the view's rotation into the particle's world matrix (what is a constant over all particles for a given view).

Share this post


Link to post
Share on other sites
Are these world particles or screen particles?

The distinction is how heavy weight they are, you say you have a transform chain LocalToWorld for each particle, this seems like a heavy weight object for standard particle systems...

If you intend to have just screen particles you can transform a point right into screen space as others have mentioned, with a projection you can set the verts straight onto the nearface of the bounding frustum....

BoundingFrustum frustum = new BoundingFrustum( ViewMatrix*ProjectionMatrix );
Vector3 [] NearFaceverts = frustum.GetCorners();
Particle[i].Vert[0] = NearFaceverts[0];
...

Share this post


Link to post
Share on other sites
Yes I could position the verts in the shader, but I have been trying to keep the same shader and pipeline as everything else. But it's looking like I'll have to special case it. Might as well do hardware instancing while I'm at it.

Share this post


Link to post
Share on other sites
the easiest way is to simply feed in the inverse view matrix of the camera, but strip out the final row (or column, depending on hand-ness) and fill the xyz pos entries with zero (as we'll be throwing in the particle's position in there in the vertex shader).

I do transformation per vertex in my game. I have a special vertex structure where I store the particle's xyz position, and also feed in color, y rotation value, scale value etc.. I don't use hardware instancing but I simply add each particle to the same vertex buffer with 0,0 to 1,1 coords and use my vertex shader do the rest

my vertex shader looks like this

BillboardParticle_VS_INPUT BillboardParticleFast_VS(BillboardParticleFast_VS_INPUT Input)
{
BillboardParticle_VS_INPUT Output;

float4x4 BillboardMatrix = (float4x4)g_IdentityMatrix;
float4x4 TranslationMatrix = (float4x4)g_InverseViewMatrix;
float4x4 ScaleMatrix = (float4x4)g_IdentityMatrix;
float4x4 RotationMatrix = (float4x4)g_IdentityMatrix;

// Build rotation matrix around Y axis
RotationMatrix[0][0] = cos(Input.Angle);
RotationMatrix[0][2] = -sin(Input.Angle);
RotationMatrix[2][0] = sin(Input.Angle);
RotationMatrix[2][2] = cos(Input.Angle);

// create Scale Matrix
ScaleMatrix[0][0] = Input.Scale;
ScaleMatrix[1][1] = Input.Scale;
ScaleMatrix[2][2] = Input.Scale;
ScaleMatrix[3][3] = 1.0f;

// Create billboard Matrix
BillboardMatrix = mul(TranslationMatrix,RotationMatrix);
BillboardMatrix = mul(ScaleMatrix,BillboardMatrix);

// force position in
BillboardMatrix[3][0] = Input.PartPos[0];
BillboardMatrix[3][1] = Input.PartPos[1];
BillboardMatrix[3][2] = Input.PartPos[2];
BillboardMatrix[3][3] = 1.0f;

// build final worldview projection matrix
float4x4 ViewProjMatrix = mul(g_ViewMatrix,g_PerspectiveMatrix);
float4x4 WorldViewProjMatrix = mul(BillboardMatrix,ViewProjMatrix);

// translate and output vertex data
Output.Pos = mul(Input.Pos,WorldViewProjMatrix);
Output.UV = Input.UV;

//20 wide spritesheet, modify uvs
Output.UV.x *= (1.0f/20.0f);
Output.UV.x+= (Input.TexSlot * (1.0f / 20.0f));

Output.Color = Input.Color;

return Output;
}


it looks pretty insane but its pretty quick (saying that, I'm pretty sure some shader pros can get it a lot slicker). The downside is that I can't use the same dynamic vertex buffer for particles that I use for my scene, but it isn't really that much of a big deal.

Edit: and yes, this requires one DrawIndexedPrimitive call to render all particles of a particular blend group.

[Edited by - DensitY on February 18, 2010 10:50:00 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this