Previous Topic (Particle Color By Speed Using Dataflow) Up (Tutorials) Next Topic (Camera Mapping Particles Using Dataflow)

Particle Color By Speed Using MAXScript


Introduction

This tutorial is a continuation of the Particle Flow Toolbox #3 example. It implements the EXACT same effect using the Script Operator which ships with 3ds Max. The main difference is the performance - see Results and Performance Notes for details.

Script Operators in Particle Flow can be used to access data from most particle channels. In particular, Krakatoa allows you to store color information per particle in the Script Vector channel and Density in the Script Float channel.

You can download the 3ds Max 9 scene file.
No additional plug-ins are necessary in order to use this file!

The Particle Flow

The Particle Flow itself is very simple:

  • A Birth Operator emits 1 million particles on frames 0 to 24.
  • The particles are positioned in the volume of the icon using a Position Icon operator. The emitter is set to sphere.
  • Speed Along Icon Arrow with Inverted direction emits particles up with Speed of 300 units per second.
  • A Force Operator' applies a spherical gravity which has been animated to have a value of 1.0 on frames 0, 100 and 200 and a value of 0.0 on frames 50, 150 and 250. The Gravity has a Decay of 0.001
  • The same Force Operator applies a Drag force to slow down particles when no Gravity is applied.
  • A Script Operator reads the speed and writes the color into the Script Vector Channel (see below).
  • A Krakatoa Options Operator tells Krakatoa to read the data from the Script Vector channel and copy it into the Vertex Color Map channel from where it can be either saved to a PRT file or rendered directly.

The 3ds Max Scene

  • In the 3ds Max viewport, the initial PF_Source01 Emitter was cloned 4 times - in this case by rotating about the origin at 90 degrees. Notice that the PF Source is cloned but the initial event will remain the same.
  • The Gravity is placed exactly in the center between all 4 emitters.
 Note that moving the Gravity away from the center can lead to very interesting variations of this scene - 
 try playing with the settings, positions, number of emitters and so on to create new designs!

The Script Operator

The Script Operator implements a simple Speed Magnitude To Color conversion function:

 on ChannelsUsed pCont do
 (
 	 pCont.useVector = true
 	 pCont.useSpeed = true
 )
 
 on Init pCont do ( )
 
 on Proceed pCont do 
 (
 	count = pCont.NumParticles()
 	for i in 1 to count do
 	(
 		pCont.particleIndex = i
 		pCont.particleVector = [0.0,0.0,4.0] + ([50.0,30.0,-50.0] * (length pCont.particleSpeed))
 	)
 )
 
 on Release pCont do ( )

The script does the following:

  • The ChannelsUsed event handler is called by Particle Flow to determine what channels will be required by the script for reading and writing. We set up only two channels:
    • Vector is a custom channel where the user can store arbitrary vector data. Krakatoa can use this data to color the particles.
    • Speed is a built-in channel containing the velocity of the particle in generic units per tick.
 Note: pCont is a variable containing a pointer to the Particle Container corresponding to the event the operator is placed in.
  • The Init event handler is called by Particle Flow at the beginning of the evaluation, but we don't use it here at all.
  • The Proceed event handler is called by Particle Flow on every integration step (sometimes more than once per frame, depending on the Integration Step settings in the System Management rollout of the Emitter). Here we put the main code that will process every single particle in the flow:
    • count is a local user variable where we put the number of particles in the container of the current event. We get this value by calling the container's method NumParticles().
    • i will be a FOR LOOP variable counting from 1 to the number of particles.
    • For each value of i, we set the particle container's .particleIndex property to that value, effectively making that particle the current one.
    • For each particle, we set the .particleVector value to the color calculated using the magnitude (length) of the speed vector, multiplied by the vector [50.0,30.0,-50.0] which represents the constant scalars used in the Data Operator. To perform the inversion of the blue value (4.0-50.0*SpeedMagnitude), we add the resulting vector to the vector [0,0,4].
 Note: The same could be expressed as:
 
 on Proceed pCont do 
 (
 	count = pCont.NumParticles()
 	for i in 1 to count do
 	(
 		pCont.particleIndex = i
 		local speedMag = length pCont.particleSpeed
 		pCont.particleVector = [50.0*speedMag, 30.0*speedMag, 4.0-50.0*speedMag]
 	)
 )
 
 While this is much easier to read, introducing local variables into the flow can slow down the script evaluation. 
 The first form does not use any local variables inside the loop and contains one vector length operation, 
 one vector multiplication by scalar and one vector addition.
 The second form uses one local variable inside the loop, three float multiplications and one float subtraction.
 A single user variable might not affect performance in a measurable way (with 400K particles, the difference between 
 these two methods was 1 seconds which is within the margin of error, but with more complex scripts, a couple seconds
 could accumulate to minutes over hundreds of frames.
  • Finally, the Release event handler is called when the evaluation finishes, but we don't use it here.

Krakatoa Settings

We will render the particles using Additive Density because we are after a plasma-like effect.

  • Use no lighting since we want a self-illuminated appearance.
  • Set the Final Pass Density to Additive and the Density Per Particle to 1.0 / -3.
  • To get a smooth result, check >Enable Motion Blur and >Jittered Motion Blur.
  • Set the Motion Blur Segments to 8 and the Motion Blur Shutter (degs) to 360.0
  • All other settings remain at defaults.
  • Right-click the QUICK RENDER button and select Active Segment [0-250] Nth: 1
  • Right-click the QUICK RENDER button again and pick Set Render Output Filename. Specify the desired location and file format (.EXR is recommended).

Finally, press the QUICK RENDER button to render the sequence.

Tips on optimizing for fast previews

  • To create a quick preview, you could reduce the Particle Count in the Birth operator to 100000 and increase the Per Particle Density to 1.0 / -2 to compensate for the lower particle count.
  • Also, to get a very rough idea of the animation, you can also disable the motion blur, but keep in mind that the drawing performance of Krakatoa is very high and the time saving might not be significant, but the quality of the final image would be much lower.

Results and Performance Notes

Below are selected frames and the full animation as QuickTime Movie. Each frame contains 4 million particles with 8 passes motion blue or 32 million point samples per frame.

On an AMD Opteron Dual Dualcore 2.2 GHz running WinXP 64 and 3ds Max 9 64-bit:

  • Frame 30 with 4 million particles and 8 passes motion blur rendered in 4 min. 19 sec. (259 seconds).
  • A frame using the Data Operator approach shown in the other tutorial took 1 min. 11 sec. which makes the script only 3.6 times slower.
  • Using 400K particles with the same settings, frame 30 took 28 seconds, 6 seconds pure drawing of 8 passes motion blur and 22 seconds particle flow calculation. This means that the system scales better than linearly - 10 times more particles should have rendered in 280 seconds but they rendered in 259 seconds.
  • Using 400K particles and the second version of the color code using an intermediate local variable to store the speed magnitude, the render time of frame 30 was consistently 29 seconds, or 1 second longer than the first method.
  • Using 4 million particles, the difference between the two scripts was 10 seconds per frame (4:19 vs. 4:29), or about 2500 seconds (around 40 minutes!) for the whole animation, which shows the vital importance of optimizing the script code when operating on millions of particles.

The resulting frames are IDENTICAL to those rendered using the Data Operator shown below:

Here is the final animation as Quicktime Movie (H.264 Codec, 1.3 MB)