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!

 Plugin disabled

Plugin attach cannot be executed.

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
	}
}