Smoke Trails         Adding some turbulence to your ribbon trails

Introduction

This snippet allows to add a simple turbulence effect to the ribbon trails.

Usage

Just add a reference to the shader in your ribbon material and you're done.

There are several parameters to control the effect:

  • curlSize, float:
The "size" (radius, diameter... not really any of them but rather similar) of the turbulence curls.
  • gravity, float3:
A constant force applied to the vertices. For instance, windy environments would have strong horizontal components, and fire would have a strong vertical component.
  • ttl, float:
A time scale. Age is calculated in the shader as a value in the range 0, 1. This parameter tells how much "time" age=1 means.
  • seed, float3:
Just three simple numbers to displace the turbulence.
  • amount, float:
How much the trail will be affected by the turbulence.


Note that the example shader uses the vertex colour alpha to determine its age. Different approaches would require to tweak the shader (for instance, using texture coordinates instead).

The files

RibbonTurbulence.cg:

void ribbon_turbulence_vp (float4 position : POSITION,
              float3 normal : NORMAL,
              float2 uv : TEXCOORD0,
              float4 col : COLOR,
              out float4 oPosition : POSITION,
              out float2 oUv : TEXCOORD0,
              out float4 oCol : COLOR,

              uniform float4x4 worldViewProj, 
              uniform float curlSize, 
              uniform float3 gravity, 
              uniform float ttl, 
              uniform float3 seed, 
              uniform float amount)
{
    float4 mypos = position;

    float3 deviation = position.xyz;

    float age = (1 - col.a) * ttl;

    mypos.xyz += gravity * age;

    // Calculate some simple turbulence
    deviation = sin ((deviation + seed) / curlSize) * age * amount;
    mypos.xyz += deviation;

    oPosition = mul(worldViewProj, mypos);

    oUv = uv;

    oCol = col;
}


The example ribbon trail material tweaked to use this shader:

vertex_program RibbonTurbulenceVp cg
{
    source RibbonTurbulence.cg
    entry_point ribbon_turbulence_vp
    profiles vs_1_1 arbvp1 vp20

    default_params
    {
        param_named_auto worldViewProj worldviewproj_matrix
        param_named curlSize float 3.5
        param_named gravity float3 0 30 0
        param_named ttl float 1
        param_named seed float3 123 -456 789
        param_named amount float 20
    }
}

material Examples/LightRibbonTrail
{
    technique
    {
        pass
        {
            vertex_program_ref RibbonTurbulenceVp
            {
            }

            lighting off
            scene_blend add
            depth_write off
            cull_hardware none
            cull_software none

            texture_unit
            {
                texture ribbonband.png 1d
                tex_address_mode clamp
                filtering none
            }
        }
    }
}

Closing note

There's a video of this effect working here.

Thanks for reading. Hope you find it useful!

Tweaking

The shader presented above works best when the object is moving in random directions (i.e. not in a straight line). It may be more suitable to use the textures coordinates instead of the position to calculate a "random" disturbance. I will demonstrate how to do that in this section which will hopefully help you understand how it works and then allow you to make your own modifications. For this to work, the v texture coordinate must increase linearly along the length of the ribbon trail.

void ribbon_turbulence_vp (float4 position : POSITION,
              float3 normal : NORMAL,
              float2 uv : TEXCOORD0,
              float4 col : COLOR,
              out float4 oPosition : POSITION,
              out float2 oUv : TEXCOORD0,
              out float4 oCol : COLOR,

              uniform float4x4 worldViewProj, 
              uniform float curlSize, 
              uniform float3 gravity, 
              uniform float ttl, 
              uniform float seed, 
              uniform float amount)
{
   float4 mypos = position;

   float age = (1 - col.a) * ttl;

   mypos.xyz += gravity * age;

   mypos.x += cos((seed+uv.v)/curlSize) * age * amount;
   mypos.z += sin((seed+uv.v)/curlSize) * age * amount;

   oPosition = mul(worldViewProj, mypos);

   oUv = uv;

   oCol = col;
}


Now the trail has a rotating motion in the XZ plane, you can of course modify this to create movement in whatever plane you like or use more complex equations to create some other type of movement that may be suitable for your application.


Alias: Smoke_Trails