Sunday, 2 June 2013

How do you add rotation to particles?

How do you add rotation to particles?

Today I was working on a particle system and I can't figure out how to give the particle billboards a rotation (so to have them spinning clockwise or counter-clockwise while facing the player). I assume the core of the problem is my complete lack of understanding of trigonometry.
So, first of all, here is my geometry shader that will produce quads that rotate around their center:
[maxvertexcount(4)]
void GeometryShaderProc( point VertexShaderInput particle[1], inout TriangleStream<PixelShaderInput> triStream ) {
  PixelShaderInput vertex = (PixelShaderInput)0;
  vertex.Color = particle[ 0 ].Color;
  vertex.Texture = particle[ 0 ].Texture;
  vertex.Position.z = particle[ 0 ].Position.z;
  vertex.Position.w = 1;

  float QuadSizeX = particle[ 0 ].Size.x / ViewportDimensions.x * 0.5;
  float QuadSizeY = particle[ 0 ].Size.y / ViewportDimensions.y * 0.5;

  float a = sin( particle[ 0 ].Position.w ) * QuadSizeX;
  float b = cos( particle[ 0 ].Position.w ) * QuadSizeY;
  float c = cos( particle[ 0 ].Position.w ) * QuadSizeX;
  float d = sin( particle[ 0 ].Position.w ) * QuadSizeY;

  // Left Top
  vertex.Position.x = particle[ 0 ].Position.x - c;
  vertex.Position.y = particle[ 0 ].Position.y - d;
  vertex.Position.z = particle[ 0 ].Position.z;
  vertex.Position.w = 1;
  vertex.Position = mul( float4( vertex.Position.xyz, 1.0 ), ViewProjection );
  vertex.TextureCoordinate = float2( 0, 0 );
  triStream.Append( vertex );
  // Left Bottom
  vertex.Position.x = particle[ 0 ].Position.x - a;
  vertex.Position.y = particle[ 0 ].Position.y + b;
  vertex.Position.z = particle[ 0 ].Position.z;
  vertex.Position.w = 1;
  vertex.Position = mul( float4( vertex.Position.xyz, 1.0 ), ViewProjection );
  vertex.TextureCoordinate = float2( 0, 1 );
  triStream.Append( vertex );
  // Right Top
  vertex.Position.x = particle[ 0 ].Position.x + a;
  vertex.Position.y = particle[ 0 ].Position.y - b;
  vertex.Position.z = particle[ 0 ].Position.z;
  vertex.Position.w = 1;
  vertex.Position = mul( float4( vertex.Position.xyz, 1.0 ), ViewProjection );
  vertex.TextureCoordinate = float2( 1, 0 );
  triStream.Append( vertex );
  // Right Bottom
  vertex.Position.x = particle[ 0 ].Position.x + c;
  vertex.Position.y = particle[ 0 ].Position.y + d;
  vertex.Position.z = particle[ 0 ].Position.z;
  vertex.Position.w = 1;
  vertex.Position = mul( float4( vertex.Position.xyz, 1.0 ), ViewProjection );
  vertex.TextureCoordinate = float2( 1, 1 );
  triStream.Append( vertex );
}
In case it isn't obvious, I'm using the w component of the input vector as the input value for the rotation.
So far so great, until I move the camera and the quads aren't facing the camera any more. So, obviously I need to rotate them.
An approach to solving that was quickly found online, so I adjusted the shader:
[maxvertexcount(4)]
void GeometryShaderProc( point VertexShaderInput particle[1], inout TriangleStream<PixelShaderInput> triStream ) {
  PixelShaderInput vertex = (PixelShaderInput)0;
  vertex.Color = particle[ 0 ].Color;
  vertex.Texture = particle[ 0 ].Texture;
  vertex.Position.z = particle[ 0 ].Position.z;
  vertex.Position.w = 1;

  float3 planeNormal = particle[ 0 ].Position.xyz - CameraPosition;
  planeNormal.y = 0.0f;

No comments:

Post a Comment