ParticleWindKernel

The ParticleWindKernel is a particle kernel which simulates wind and air resistance. It duplicates the functionality of Nuke’s ParticleWind node.

Change the paWind parameter to set the direction of the wind and the paDrag parameter to alter the air resistance.

// A particle kernel which simulates wind
kernel ParticleWindKernel : ImageComputationKernel<ePixelWise>
{
  // Declare our images for the particle attributes we're interested in
  Image<eReadWrite> p_velocity; // Must be a 3 channel image
  Image<eRead> p_conditions; // This is a pseudo-attribute created from the Conditions/Region knobs
  Image<eRead> p_mass;
  Image<eRead> p_startTime;

  param:
    float3 _wind; // The wind velocity
    float _drag; // The drag coefficient
    float _dt; // The time step
    float _endTime; // The end of the current time step

  // Define our parameters. The ones starting with "_" are provided by the
  // ParticleBlinkScript op. The others will have knobs created for them.
  // We use the "pa" prefix to avoid name clashes with other knobs on the op.
  void define() {
    defineParam(_wind, "paWind", float3(1.0f, 0.0f, 0.0f));
    defineParam(_drag, "paDrag", 0.5f);
    defineParam(_dt, "_dt", 1.0f);
    defineParam(_endTime, "_endTime", 1.0f);
  }

  // This is called for each particle
  void process() {
    // Only process if the conditions are met
    if ( p_conditions(0) ) {
      // Work out the velocity of the particle relative to the air
      float3 difference = _wind-p_velocity();
      float l = length(difference);
      if ( l != 0.0f ) {
        // Calculate the unit vector for the resulting force
        float3 forceDirection = difference/l;
        // Work out the time to apply the force over. For most particles
        // this would be the same as _dt, but not for particles created
        // part way through their first time step.
        float dt =  max(0.0f, min(_dt, float(_endTime - p_startTime(0))));
        // For air resistance we need exponential decay over dt
        float t = 1.0f-pow(1.0f-_drag, dt);
        // Apply the force
        p_velocity() += difference*t/p_mass();
      }
    }
  }
};