Table of contents
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!
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 } }