Table of contents
Description
Ever wanted a particle to use a random texture instead of only being limited to one? If so, tough luck, you can't change that! But what we can do is use a workaround with shaders to make it look like we're using random textures, by making the particle use one texture with our different images on it.
So how do we assign each particle a random number to use, to pick a texture? With one of ogre's particle effects, the thing that tints particles random colors! Unfortunately this also means that we can't actually use these random tints, as this makes all of the particles the same color. You also can't change the color over time with a ColourFader, but you can at least change the alpha that way.
I also only have the shader in hlsl at the moment, but if you want to write up a glsl or cg version, then go ahead and post it here when you're done!
Usage
Start by adding this to each particle you want this shader to be used for.
colour_range_start 1 1 1 colour_range_end 0 1 1
We'll be using the random red tint each particle receives to decide which tile to use.
Otherwise, all you need to do is just add a reference to the vertex and fragment programs in your material, with appropriate parameters.
randomParticle.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.r); if (selectedTile == numTilesTotal) selectedTile = numTilesTotal - 1; oUv.x = (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, float4 color : COLOR0, uniform sampler2D tex : register(s0)) : COLOR { // keep any transparency we're using in the particle, like from a ColourFader float4 oColor; oColor = tex2D(tex, uv.xy); oColor.a *= color.a; return oColor; }
randomParticle.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. - Set your particle emitter's random colour value to something so the red can be from 1 to 0. The red value won't actually be used to change the tint of the texture, but instead it will be used to move along the UV coordinates. Example: colour_range_start 1 0 0 colour_range_end 0 0 0 If you want colored particles, you need to color them yourself in photoshop or something. */ vertex_program randomParticle_vp hlsl { source randomParticle.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 randomParticle_fp hlsl { source randomParticle.hlsl entry_point main_fp target ps_2_0 }
Example material
material Particles/Dust { receive_shadows off technique { pass { lighting off scene_blend alpha_blend depth_write off vertex_program_ref randomParticle_vp { param_named numTilesU float 8 param_named numTilesV float 1 } fragment_program_ref randomParticle_fp { } texture_unit { texture "saa dust particles.dds" tex_address_mode clamp } } } }
Example particle
particle_system dust { quota 200 material Particles/Dust particle_width 0.7 particle_height 0.7 billboard_type point billboard_rotation_type vertex emitter Box { angle 90 duration 0.4 emission_rate 50 velocity 1 repeat_delay 0.1 time_to_live 0.4 position 0 0 -0.5 width 1 height 1 depth 1 // for the random particle picker colour_range_start 1 1 1 colour_range_end 0 1 1 } affector ColourFader { alpha -3 } affector Scaler { rate 4 } affector Rotator { rotation_speed_range_start -360 rotation_speed_range_end 360 rotation_range_start -360 rotation_range_end 360 } }