Billboarded sprite transform

Started by
6 comments, last by DensitY 14 years, 1 month ago
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?
Advertisement
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.
Maybe this helps.
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.
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).
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.Vert[0] = NearFaceverts[0];
...

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.
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]

This topic is closed to new replies.

Advertisement