TSE/Precipitation

From TDN

This page is a Work In Progress.

Contents

Introduction

The Precipitation object is extremely useful for doing rain, snow, or just about any other falling particle effect. In TGEA the Precipitation effect has been extended to support shaders, animated drops, transformed volumes, and more.

PrecipitationData Datablock

To use Precipitation in your mission you first need to define a PrecipitationData datablock. If your unsure where this datablock belongs, place it in the demo/server/scripts/environment.cs in the default TGEA installation.

The datablock has the following parameters:


PrecipitationData Fields
Field Name Type Default Value Description
soundProfile AudioProfilePtr NULL Points to the AudioProfile used to produce the ambient sound of the precipitation. If null no sound is played.
dropTexture Filename "" The texture file to use for rendering drop particles.
dropShader String "" The name of the shader used for drop particles. If empty or invalid fixed function rendering is used.
dropsPerSide S32 4 This defines how many drops are on one side of the drop texture. This value is squared to determine the number of drop frames/variations in the texture.
splashTexture Filename "" The texture file to use for rendering splash particles.
splashShader String "" The name of the shader used for splash particles. If empty or invalid fixed function rendering is used.
splashesPerSide S32 2 This defines how many splashes are on one side of the splash texture. This value is squared to determine the number of splash frames/variations in the texture.


Here is an example of a PrecipitationData datablock that uses the default shader, has 16 drop frames, and 4 splash frames.

datablock PrecipitationData(HeavyRain)
{
   soundProfile = "HeavyRainSound";

   dropTexture = "~/data/environment/rain";
   dropShader = "PrecipShader";
   dropsPerSide = 4;
   
   splashTexture = "~/data/environment/water_splash";
   splashShader = "PrecipShader";
   splashesPerSide = 2;
};

Shader

The datablock now has the dropShader and splashShader fields which allow you to specify a vertex and pixel shader program to use for rendering the precipitation particles. The common ShaderData object would look like so:

new ShaderData( PrecipShader )
{
   DXVertexShaderFile   = "shaders/precipV.hlsl";
   DXPixelShaderFile    = "shaders/precipP.hlsl";
   pixVersion = 1.1;
};

If working within the TGEA demo demo/client/scripts/shader.cs is a good location for it, but any client side script location will do.

shaders/precipV.hlsl

The default vertex shader does a simple transform, passes thru the ambient color, and conditionally calculates the distance fade value. By moving the fade calculation to the shader we save some extra per-vertex work on the CPU.

//*****************************************************************************
// Precipitation vertex shader
//*****************************************************************************
#define IN_HLSL
#include "shdrConsts.h"


//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
struct Vert
{
	float4 position	: POSITION;
	float4 texCoord	: TEXCOORD0;
};

struct Conn
{
	float4 position : POSITION;
	float4 texCoord	: TEXCOORD0;
	float4 color : COLOR0;
};

//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
Conn main(  Vert In, 
            uniform float4x4 modelview : register(VC_WORLD_PROJ),
	    uniform float2 fadeStartEnd : register(C4),
	    uniform float3 cameraPos : register(C5),
	    uniform float3 ambient : register(C6)
)
{
   Conn Out;

   Out.position = mul(modelview, In.position);
   Out.texCoord = In.texCoord;
   Out.color = float4( ambient.r, ambient.g, ambient.b, 1 );

   // Do we need to do a distance fade?
   if ( fadeStartEnd.x < fadeStartEnd.y ) 
   {
      float distance = length( cameraPos - In.position );
      Out.color.a = abs( clamp( ( distance - fadeStartEnd.x ) / ( fadeStartEnd.y - fadeStartEnd.x ), 0, 1 ) - 1 );
   }

   return Out;
}

shaders/precipP.hlsl

The default pixel shader is very optimal and simply modulates the fragment by the input color.

//-----------------------------------------------------------------------------
// Structures                                                                  
//-----------------------------------------------------------------------------
struct Conn
{
   float2 texCoord : TEXCOORD0;
   float4 color : COLOR0;
};

struct Frag
{
   float4 col : COLOR0;
};

//-----------------------------------------------------------------------------
// Main                                                                        
//-----------------------------------------------------------------------------
Frag main( Conn In,
           uniform sampler2D diffuseMap : register(S0)
)
{
   Frag Out;

   Out.col = tex2D(diffuseMap, In.texCoord) * In.color;

   return Out;
}

Custom Shaders

A custom shader could be used for precipitation to perform application specific effects. In the shader you could modify colors, tweak the light calculation, apply special time based distortions, apply specular effects, and more. See the Materials Getting Started Guide for more details on custom shaders.

Textures

The textures defined in the precip datablock can be used to provide individual particle variations or to animate the falling or splash particles.


The order of the frames when animating precipitation particles




When the particles are animated, either by setting animateSplashes or dropAnimateMS (see below), the frame order follows the a left-to-right, top-to-bottom order. The number for frames is defined by the dropsPerSide or splashesPerSide datablock field depending if this is the dropTexture or the splashTexture.

Precipitation SceneObject

Once you have your PrecipitationData datablock, ShaderData, and textures your ready to add the Precipitation scene object in to your mission.

The scene object has the following parameters:


Precipitation Fields
Field Name Type Default Value Description
numDrops S32 1024 The maximum number of drops in the system.
boxWidth F32 200 The width of the precipitation volume.
boxHeight F32 100 The height of the precipitation volume.
Rendering
soundProfile AudioProfilePtr NULL Points to the AudioProfile used to produce the ambient sound of the precipitation. If null no sound is played.
Collision
dropTexture Filename "" The texture file to use for rendering drop particles.
Movement
dropShader String "" The name of the shader used for drop particles. If empty or invalid fixed function rendering is used.
Turbulence
dropsPerSide S32 4 This defines how many drops are on one side of the drop texture. This value is squared to determine the number of drop frames/variations in the texture.

Effects

(discuss effects you can apply)

Glow

Volumetric

Transforms

Performance

The current performance of Precipitation is on par if not faster than that of TGE. The typical performance bottleneck is the simulation and packing of particles into the vertex buffers for rendering.

The simulation is a fixed cost and is done once per tick if the precipitation is visible (precipitation that is zoned off or behind the camera is not simulated). Reducing the number of particles and disabling collision are the best methods to improve the performance of the simulation.

During tick interpolation, which is done every frame, turbulence is applied. By disabling useTurbulence you bypass a costly mSin and mCos operation per visible particle.

Packing the particles for rendering can be costly depending on the specific settings of the precipitation. Setting useTrueBillboards to true results in much less calculations per packed particle and is much better on large amounts of drops. Also consider that enabling glow will force the particles to be packed twice, once for normal rendering and once for rendering to the glow buffer.