Animated Particle (HLSL)        

Description


I found another shader on this wiki about an animated particle shader, but it required the use of a volumetric DDS texture (Explosion). Not only is finding a program that exports to that hard to find, but those that I have found usually spit out a huge uncompressed file - for the mud particle texture I'm using, it came out to be 2MB! With this method, you just use a 2D image split into rows and columns. Much easier to use!

So how does it work? With particles you can add affectors that do stuff to each particle, such as decreasing its opacity over time. That's what we're going to use to make sure your particle looks animated!

A drawback with this method is that if you want a fade out effect, you'll need to add that in your texture, since we'll be using the transparency number for something else.

I only have it in hlsl though, so if you want to convert it to cg or glsl then go ahead, just add it to this page when you're done!

 Plugin disabled
Plugin attach cannot be executed.

 Plugin disabled
Plugin attach cannot be executed.

Usage


Just add a reference to the vertex and fragment programs in your material, providing the parameters for how many tiles are in your image.

In your particle, make sure you include this somewhere, changing the number to something appropriate depending on speed:

affector ColourFader {
	alpha -3
}


Okay anyway on with the shader.

animatedParticle.hlsl

void main_vp(float2 uv : TEXCOORD0,
	     float4 position : POSITION,
	     float4 color : COLOR0,
			 
	     out float2 oUv : TEXCOORD0,			 
	     out float4 oPosition : POSITION,
	     out float4 oColor : COLOR0,
			 
	     // if these are passed as ints, then it doesn't work for some reason
	     uniform float numTilesU,
	     uniform float numTilesV,
			 
	     uniform float4x4 worldViewProj)
{
	// I have no idea why, but if we don't cast these to ints then it gets screwed up
	int iNumTilesU = (int)numTilesU;
	int iNumTilesV = (int)numTilesV;
	
	int numTilesTotal = iNumTilesU * iNumTilesV;
	int selectedTile = (int)(numTilesTotal * color.a);
	
	if (selectedTile == numTilesTotal)
		selectedTile = numTilesTotal - 1;
	// the "1 - " bit is because otherwise it goes from right to left
	oUv.x = 1 - ((uv.x + selectedTile % iNumTilesU) / iNumTilesU); ///selectedTile;
	oUv.y = (uv.y + selectedTile / iNumTilesU) / iNumTilesV; ///selectedTile;

	// pass these on
	oPosition = mul(worldViewProj, position);
	oColor = color;
}

float4 main_fp (float2 uv : TEXCOORD0,
		uniform sampler2D tex : register(s0))
: COLOR
{
	return tex2D(tex, uv.xy);
}

animatedParticle.material

/*
	Instructions:
	
	- Have a reference to both the vertex program and fragment program in your material
	- Set the parameters of the vertex program correctly, according to the number of
	  stacks/slices in your texture
	- Give your particle emitter a ColourFader that changes the alpha over time.
	  The alpha value won't actually be used to change the transparency of the texture,
	  but instead it will be used to move along the UV coordinates over time.
*/

vertex_program animatedParticle_vp hlsl {
	source animatedParticle.hlsl
	entry_point main_vp
	target vs_2_0
	
	default_params {
		param_named numTilesU float 1
		param_named numTilesV float 1
		param_named_auto worldViewProj worldviewproj_matrix
	}
}

fragment_program animatedParticle_fp hlsl {
	source animatedParticle.hlsl
	entry_point main_fp
	target ps_2_0
}

example material

material Particles/Mud {
	receive_shadows off
	
	technique {
		pass {
			lighting off
			scene_blend alpha_blend
			depth_write off
			
			vertex_program_ref animatedParticle_vp {
				param_named numTilesU float 8
				param_named numTilesV float 1
			}
			
			fragment_program_ref animatedParticle_fp {
			}
 
			texture_unit {
				texture "mudparticle.dds"
				tex_address_mode clamp
			}
		}
	}
}

My particle

particle_system mud {
	quota 100
	material Particles/Mud
	particle_width	1.2
	particle_height	1.2
	billboard_type point
	sorted true

	emitter Box {
		angle 90
		duration 0.3333
		emission_rate 20
		velocity 0.5
		repeat_delay 0.1
		time_to_live 0.3333
		
		position 0 0 -0.5
		
		width 1
		height 1
		depth 1
	}
	affector ColourFader {
		alpha -3
	}
}