FumeFX Scripting

 

 

Adding/Removing Objects, Lights, Sources

fumeFXcmd - addNode <string>nodename fume;

fumeFXcmd( fume, addNode=<string>nodename)

Use this flag to attach FumeFX Sources, Effectors, collision proxies, fields and lights to FumeFX.  It is equivalent to selecting a node in the FumeFX Relationship Manager.

fumeFXcmd - removeNode <string>nodename fume;

fumeFXcmd( fume, removeNode=<string>nodename)

Use this flag to remove FumeFX Sources, Effectors, collision proxies, fields and lights from FumeFX.  It is equivalent to de - selecting a node in the FumeFX Relationship Manager.

fumeFXcmd - numSources fume;

fumeFXcmd( fume, numSources=True)

Returns number of sources assigned to FumeFX.

fumeFXcmd - getSource <int>index fume;

fumeFXcmd( fume, getSource=<int>index)

Returns source with specified index. Index ranges form 0 to numSources - 1.

fumeFXcmd - numObjects fume;

fumeFXcmd( fume, numObjects=True)

Returns a number of collision object proxies that are assigned to FumeFX.

fumeFXcmd - getObject <int>index fume;

fumeFXcmd( fume, getObject=<int>index)

Returns collision object proxy with specified index. Index ranges form 0 to numObjects - 1.

fumeFXcmd - numEffectors fume;

fumeFXcmd( fume, numEffectors=True)

Returns number of effectors assigned to FumeFX.

fumeFXcmd - getEffector <int>index fume;

fumeFXcmd( fume, getEffector=<int>index)

Returns effector with specified index. Index ranges form 0 to numEffectors - 1.

fumeFXcmd - numLights fume;

fumeFXcmd( fume, numLights=True)

Returns number of lights assigned to FumeFX.

fumeFXcmd - getLight <int>index fume;

fumeFXcmd( fume, getLight=<int>index)

Returns light with specified index. Index ranges form 0 to numLights - 1.

 

 

Preview Window

fumeFXcmd - makePreview <int>startFrame <int>endFrame <int>quality <int>width fume;

fumeFXcmd( fume, makePreview=[<int>startFrame, <int>endFrame, <int>quality, <int>width])

This command will generate preview. If width is 0, size is left as it is. quality - range is from 1 to 5.

fumeFXcmd - resizePreview <int>width fume;

fumeFXcmd( fume, resizePreview=<int>width)

Resizes preview window to specified size.

 

 

Simulation Control

fumeFXcmd - runSimulation <int>simMode fume;

fumeFXcmd( fume, runSimulation=<int>simMode)

This does exactly the same as hitting the start button on the FumeFX Floater.  Simulation will run from StartFrame to EndFrame.

simMode:

0 - Default Simulation

1 - Simulation from Initial State

2 - Wavelet Simulation

3 - Retimer

fumeFXcmd - continueSimulation <int>simMode fume;

fumeFXcmd( fume, continueSimulation=<int>simMode)

This does exactly the same as hitting the continue button on the FumeFX Floater

simMode:

0 - Default Simulation

1 - Simulation from Initial State

2 - Wavelet Simulation

fumeFXcmd - stopSimulation fume;

fumeFXcmd( fume, stopSimulation=True)

This is equivalent to pressing the Stop button in the status window.

fumeFXcmd - cancelSimulation fume;

fumeFXcmd( fume, cancelSimulation=True)

This is equivalent to pressing the Cancel button in the status window.

fumeFXcmd - setInitialStateFile <string>filename fume;

fumeFXcmd( fume, setInitialStateFile=<string>filename)

Use this flag to set Initial State file to be used with Initial State Simulation Mode.

fumeFXcmd - getInitialStateFile fume;

fumeFXcmd( fume, getInitialStateFile=True)

Returns Initial State file name.

fumeFXcmd - saveOutput <string>filename fume;

fumeFXcmd( fume, saveOutput=<string>filename)

This saves a .fxd type output file; note,  you must enter the full file name.

fumeFXcmd - saveSimulation <string>filename fume;

fumeFXcmd( fume, saveSimulation =<string>filename)

This saves a .fdc type simulation file; note, you must enter full file name.

fumeFXcmd - loadSimulation <string>filename fume;

fumeFXcmd( fume, loadSimulation =<string>filename)

This will load a .fdc file into the FumeFX.

fumeFXcmd - getPath <string>type fume;

fumeFXcmd( fume, getPath=<string>type)

This returns the current base output file name without the frame number suffix.

cacheType:

default - path for Deault Sim. caches

wavelet - path for Wavelet Sim. caches

retimer - path for Retimer caches

illummap - path for Illumination Map

preview - path for preview animation clip

fumeFXcmd - setPath <string>filename <string>type - match - nocheck fume;

fumeFXcmd( fume, setPath=[<string>filename, <string>type], match=True nocheck=True)

This sets the current base output file name for specified path type.

cacheType:

default - path for Deault Sim. caches

wavelet - path for Wavelet Sim. caches

retimer - path for Retimer caches

illummap - path for Illumination Map

preview - path for preview animation clip

Optional flags:

match - if grid is of different proportions, FumeFX will be matched to it.

nocheck - path validity won't be checked.


 

FumeFX MEL/Python Functions for Accessing the Simulation

By learning to use FumeFX functions created for MEL/Python, you can do almost anything that you want with FumeFX - including things not provided for in the default user interface.  It is possible for you to plug in script between all significant phases of the simulation or even disable some simulation steps altogether.

 

If you create a script that will modify all of the voxels in a simulation (which could be tens of millions), it will execute at reasonable speeds, measured in seconds.

To get the feel of it, here is an example script:

 

// MEL

proc ffx_mel_PostObjects( string $node )

{

fumeFXcmd - clearObjectList $node;

if ( !`fumeFXcmd - setObject "smoke" $node`)

error "Smoke channel is not allocated!";

return;

$nx = `fumeFXcmd - getnx $node`;

$ny = `fumeFXcmd - getny $node`;

$nz = `fumeFXcmd - getnz $node`;

for($i=0; $i<$nx; ++$i)

for($j=0; $j<$ny; ++$j)

for($k=0; $k<$nz; ++$k)

{

$val = $k / (float)$nz;

ffxDynaSetChannelCmd - function "sv" 0 - parami3 $i $j $k - valued1 $val;

}

}

 

 

ffx_mel_PostObjects is a ???callback??? function that FumeFX will call in every frame of the simulation after it has applied all sources and objects.  It will go though all voxels in the adaptive grid (nx, ny and nz are dimensions of the FumeFX adaptive grid) and initialize the Smoke channel with a vertical gradient going from 0 to 1 over the local Y - axis.  Channel is a set using voxel coordinates. (Mind the smoke opacity gradient to view results.)

 

Note:

While Maya uses lefthand coordinate system, FumeFX internally uses righthand coordinate system.

If you request and set FumeFX channel data in local or world coordinates, you'll never know there's any difference. But if you work in voxel (or index) coordinates (as in given example), you might want to consider conversion rules:

FumeFX to Maya (x,y,z) => (x,  z, - y)

Maya to FumeFX (x,y,z) => (x, - z,  y)

 

 

While setting channel values one voxel at the time can be convenient, it might be simpler (and much faster) to set values for entire blocks of voxels at the time. Here's that same script using block procedures:

 

# Python

import maya.cmds as cmds

# * * *

def postObjects(self):

{

nx = cmds.fumeFXcmd( self.nodeName, getnx=True )

ny = cmds.fumeFXcmd( self.nodeName, getny=True )

nz = cmds.fumeFXcmd( self.nodeName, getnz=True )

a = [k/float(nz) for k in range(nz)]

a = (a*ny)*nx

cmds.fumeFXcmd( self.nodeName, setFieldValues=[ 'smoke', str(a) ] )

}

 

 

The first method (element wise) is more suitable for use in MEL (as second method runs much slower in MEL), while the second method (block wise) gives significant speed improvements in Python (while first method runs slower in Python). Differences concern mostly set (rather than get) procedures. Second method (block wise) uses a lot more memory than the first method.

 

Note that, with first method, you need to setup object and channel you want to use prior calling ffxDynaGetChannelCmd or ffxDynaSetChannelCmd procedures. You can do that by calling fumeFXcmd - setObject for every channel and every node you intend to use.

 

 

MEL/Python in FumeFX Simulation

How it works:

When you click Create Script Template in the Script rollout, FumeFX will create a MEL/Python template in which you can write your scripts.  In it there are certain procedures that FumeFX will call during simulation.  All of them are called once for each step of the simulation, unless otherwise noted.

 

Callback Functions

Note: Currently, the PostAdvection and PostPressure functions are for experimental use only, but are provided for those who are familiar with their use.

 

 

ffx_mel_PreSim

preSim

Called once - at the beginning of simulation, before the first step has started, but after possible snapshot or stop/continue data has been loaded.

ffx_mel_PostSim

postSim

Called once - after the last step of the simulation has ended and while the simulation results are still in memory.

ffx_mel_PostObjects

postObjects

Think of this as a scripted Source.  It is called after the Adaptive grid has adjusted and FumeFX Sources, objects, and forces have all been applied.  Here, you can additionally initialize the grid any way you like.

ffx_mel_Vorticity

vorticity

This is the only place where Vorticity can be customized. The AddVort function allows every voxel can have its own Vorticity strength.  Be aware that the stability of simulation can become unreliable when using values greater than 1.

ffx_mel_PostForces

postForces

Buoyancy, Gravity, Vorticity, Motion Drag have been applied. Here you can apply custom forces such as: radial gravity, motion drag dependent on object distance, etc???

ffx_mel_PostAdvect

postAdvect

This is called after Velocities have moved through one step.  If you have disabled FumeFX's Advection phase, you could theoretically write your own version in this function.

ffx_mel_PostPressure

postPressure

This is called after pressure has been applied.

ffx_mel_PostDiffuse

postDiffuse

This is called after movement of Smoke and Fuel and their diffusion and dissipation.  This is the proper time to set Fuel and Temperature values to control fires.

ffx_mel_PostStep

postStep

This is called following a whole simulation step, after the Fuel has been burned and diffusion and dissipation applied.  You can set any kind of influence between channels here.  If you have disabled FumeFX's Burn phase, you could use this to burn Fuel your way.

ffx_mel_PostLoad

postLoad

This is called each time FumeFX loads cache. This is the only callback that can be used even when not simulating.

 

 

Skipping FumeFX Simulation Phases

If you want to skip certain FumeFX simulation phases completely, use the following flags before simulation start (usually in ffx_mel_PreSim/preSim callback):

 

fumeFXcmd - skipForces fume;

fumeFXcmd( fume, skipForces=True)

Skips applying forces phase during simulation.

fumeFXcmd - skipAdvection fume;

fumeFXcmd( fume, skipAdvection=True)

Skips applying advection phase during simulation.

fumeFXcmd - skipPressure fume;

fumeFXcmd( fume, skipPressure=True)

Skips applying pressure phase during simulation.

fumeFXcmd - skipBurn fume;

fumeFXcmd( fume, skipBurn=True)

Skips applying burn phase during simulation.

 

This is not recommended unless you have experience.

 

A few examples of when you can skip certain phases are:

 

You can skip Pressure and Advection phase if you simulate only the effects of diffusion.

 

You can skip the Burn phase if you want to burn Fuel some other way.

 

You can skip Forces if you want to apply buoyancy, gravity or motion drag in some specific way, such as depending on position or distance from objects.

 

 

FumeFX Channel Access

You can access channel values in four coordinates: index, voxel, object (local) and world.

 

Index coordinates require (integer) index of voxel you want to access. Remember this is internal FumeFX index; this method should be used mostly when you want to access every voxel and you don't care where it is. Index coordinates range from 0 to nx*ny*nz - 1.

 

Voxel coordinates are integer coordinates of voxels in FumeFX grid. They span from 0 to nx - 1 for first coordinate, from 0 to ny - 1 for second coordinate, and from 0 to nz - 1 for third coordinate. That for nx is the number of voxels in first coordinate in adaptive grid in current frame, etc.. You can obtain nx using getnx flag, etc.. You can use this method if you know what you're doing. You can transform voxel (i,j,k) to index (ix) coordinates as ix = i*ny*nz+j*nz+k.

 

Object (local) coordinates are float coordinates in relation to FumeFX transform node pivot (i.e. local FumeFX coordinates). If FumeFX location is [0,0,0] (as by default), you should use object coordinates over world coordinates, as object coordinates are a bit faster. FumeFX dimensions are exposed through FumeFX nodes: width, length, and height.

 

World coordinates are float coordinates in world space.

 

There are slight speed differences between coordinates; from fastest to slowest: index < voxel < object < world. However, since coordinates transformation are done internally, regardless which one you choose, it will still be the fastest part of the script.

 

 

Note that you can access only channels which are used by FumeFX. During simulation that means that you can access fuel only if it's beeing simulated. Outside simulation that means that you can access fuel only if it's beeing displayed in viewport or preview window.

 

 

Get Channel Functions

 

Element wise procedures

 

Element wise procedures enable you to access one voxel at the time.

 

NOTE!

Don't forget to call setObject and register node and channel which you plan to access, before using element wise procedures.

 

 

 

ffxDynaGetChannelCmd - function <string>functionName <int>fume_index

- parami1 <int>index_coords

- parami3 <int>voxel_coords1 <int>voxel_coords2 <int>voxel_coords3

- paramd3 <float>float_coordsX <float>float_coordsY <float>float_coordsZ;

ffxDynaGetChannelCmd( function=[<string>functionName,  <int>fume_index],

parami1=<int>index_coords,

parami3=[<int>voxel_coords1, <int>voxel_coords2, <int>voxel_coords3],

paramd3=[<float>float_coordsX, <float>float_coordsY, <float>float_coordsZ])

Get voxel channel value.

Function names consist of two or three letters. If you need channel value, first letter specifies channel:

s - smoke

f - fuel/fire

t - temperature

v - velocity

c - color

Color values are RGB float values ranging from 0.0 to 1.0.

Second letter specifies query coordinates:

i - index

v - voxel

l - local

w - world

If you need coordinate transform, first letter should be 'o', second letter specifies query coordinates, third letter specifies transform coordinates.

 

Optional parameters are conditioned by function name. You should use parami1 flag when accessing index coordinates, parami3 flag when accessing voxel coordinates, and paramd3 when accessing local or world coordinates.

Fume index is 0 - based index of FumeFX grid you want to access. Indices of FumeFX grids correspond to order in which they were registered with setObject flag; if multiple channels over multiple nodes have been registered, order of indices correspond to first registered channel for each node (see setObject man page for more info).

 

Return values are conditioned by function name. Smoke, fuel and temperature queries will return float value. Velocity and color queries will return float array (of length 3, for XYZ or RGB). Coordinate transform queries will return integer in case of index transform, integer array (of length 3) in case of voxel transform, and float array (of length 3) in case of local or world transform.

 

Example:

 

// MEL

$node = "fumeFXShape1";

// prepare objects and data

fumeFXcmd - clearObjectList $node;

if ( !`fumeFXcmd - setObject "smoke" $node` )

error "Smoke channel is not allocated!";

int $nx = `fumeFXcmd - getnx $node`;

int $ny = `fumeFXcmd - getny $node`;

int $nz = `fumeFXcmd - getnz $node`;

 

// get smoke value from center of the grid

float $smoke_val = `ffxDynaGetChannelCmd - function "si" 0 - parami1 ($nx*$ny*$nz/2)`;

// get smoke value from top center voxel

$smoke_val = `ffxDynaGetChannelCmd - function "sv" 0 - parami3 ($nx/2) ($ny/2) $nz`;

// get smoke value from voxel containing point [ - 12.3, 73.2, 18.5] in object coordinates

$smoke_val = `ffxDynaGetChannelCmd - function "sl" 0 - paramd3 - 12.3 73.2 18.5`;

if ( !`fumeFXcmd - setObject "fuel" $node` )

error "Fuel channel is not allocated!";

// get fuel value from voxel containing point [41.0, 13.3, 2.2] in world coordinates

$smoke_val = `ffxDynaGetChannelCmd - function "fw" 0 - paramd3 41.0 13.3 2.2`;

 

fumeFXcmd - setObject "coords" $node;

// convert point [41.0, 13.3, 2.2] from world to voxel coordinates

int $vox_coords[] = `ffxDynaGetChannelCmd - function "owv" 0 - paramd3 41.0 13.3 2.2`;

 

// get average value of smoke in grid

float $average = 0;

int $voxels = $nx*$ny*$nz;

for ( $i=0; $i<$voxels; ++$i)

$average += `ffxDynaGetChannelCmd - function "si" 0 - parami1 $i`;

$average /= $voxels;

 

 

These functions will return undefined if you ask for non - existing coordinates or coordinates outside of the grid.

 

Block wise procedures

 

Block wise procedures enable you to access blocks of voxels at the time.

 

fumeFXcmd - getFieldValues <string>field

- useIndexRange <int>start <int>end

- useVoxelRange <int>startX <int>startY <int>startZ <int>endX <int>endY <int>endZ

- useObjectRange <float>startX <float>startY <float>startZ <float>endX <float>endY <float>endZ

- useWorldRange <float>startX <float>startY <float>startZ <float>endX <float>endY <float>endZ fume;

fumeFXcmd( fume, getFieldValues=<string>field,

useIndexRange=[<int>start, <int>end],

useVoxelRange=[<int>startX, <int>startY, <int>startZ, <int>endX, <int>endY, <int>endZ],

useObjectRange=[<float>startX, <float>startY, <float>startZ, <float>endX, <float>endY <float>endZ],

useWorldRange=[<float>startX, <float>startY, <float>startZ, <float>endX, <float>endY, <float>endZ])

Get array of voxel channel values. getFieldValues flag accepts following values:

- "smoke"

- "fuel"

- "temp"

- "velo"

- "color"

Optional flags enable you to define block of voxels for which you want channel data. If no optional flags are given, procedure returns channel values for entire grid.

Color values are RGB float values ranging from 0.0 to 1.0.

When velocity or color channels are queried, returning array is three times longer than number of voxels (as it contains XYZ or RGB values).

 

Returns NULL if there's no intersection between FumeFX adaptive box and specified block area. Returns False on error.

 

Example:

 

# Python

import maya.cmds as cmds

nodeName = 'fumeFXShape1'

 

# prepare objects and data

nx = cmds.fumeFXcmd ( nodeName, getnx=True )

ny = cmds.fumeFXcmd ( nodeName, getny=True )

nz = cmds.fumeFXcmd ( nodeName, getnz=True )

 

# get (entire) smoke channel

smoke_field = cmds.fumeFXcmd ( nodeName, getFieldValues='smoke' )

if smoke_field != None:

num_voxels = len( smoke_field ) # get number of voxels in grid

average = sum( smoke_field ) / num_voxels # get average value of smoke in grid

else:

print "smoke field is empty"

 

# * * *

 

# process smoke channel in blocks to conserve memory

block_size = ny*nz

num_voxels = nx*ny*nz

for i in xrange( 0, num_voxels - 1, block_size):

smoke_field = cmds.fumeFXcmd ( nodeName, getFieldValues='smoke', useIndexRange=[ i, i+block_size - 1] )

if smoke_field != None:

proc_smoke( smoke_field )

else:

smoke_field = cmds.fumeFXcmd ( nodeName, getFieldValues='smoke', useIndexRange=[ i, num_voxels - 1] )

if smoke_field != None:

proc_smoke( smoke_field )

 

# get smoke channel block containing all points bounded by [ - 10, 13.75, - 32.17] and [22.1, 70, - 1.2] in local coordinates

smoke_field = cmds.fumeFXcmd ( nodeName, getFieldValues='smoke', useObjectRange=[ - 10, 13.75, - 32.17, 22.1, 70, - 1.2] )

 

 

 

Set Channel Functions

 

Element wise procedures

 

Element wise procedures enable you to access one voxel at the time.

 

NOTE!

Don't forget to call setObject and register node and channel you plan to access before using element wise procedures.

 

 

 

ffxDynaSetChannelCmd - function <string>functionName <int>fume_index

- parami1 <int>index_coords

- parami3 <int>voxel_coords1 <int>voxel_coords2 <int>voxel_coords3

- paramd3 <float>float_coordsX <float>float_coordsY <float>float_coordsZ

- valued1 <float>value

- valued3 <float>value1 <float>value2 <float>value3;

ffxDynaSetChannelCmd( function=[<string>functionName,  <int>fume_index],

parami1=<int>index_coords,

parami3=[<int>voxel_coords1, <int>voxel_coords2, <int>voxel_coords3],

paramd3=[<float>float_coordsX, <float>float_coordsY, <float>float_coordsZ],

valued1=<float>value,

valued3=[<float>value1 <float>value2 <float>value3])

Set voxel channel value.

Function names consist of two letters. First letter specifies channel:

s - smoke

f - fuel/fire

t - temperature

v - velocity

c - color

u - turbulence

o - vorticity

Color values are RGB float values ranging from 0.0 to 1.0.

Second letter specifies query coordinates:

i - index

v - voxel

l - local

w - world

 

Optional parameters are conditioned by function name. You should use parami1 flag when accessing index coordinates, parami3 flag when accessing voxel coordinates, and paramd3 when accessing local or world coordinates. You should also use valued1 when setting smoke, fuel, temperature or vorticity channels, and valued3 when setting velocity, color or turbulence channels.

 

Note about vorticity and turbulence; used in simulation, they are cumulative with UI defined global Vorticity and Turbulence. If you wish to use only the scripted values, you must set Vorticity and Turbulence strength in the UI to 0. Also note, vorticity strengths above 1 may, in rare cases, make the simulation unstable.

 

Fume index is 0 - based index of FumeFX grid you want to access. Indices of FumeFX grids correspond to order in which they were registered with setObject flag; if multiple channels over multiple nodes have been registered, order of indices correspond to first registered channel for each node (see setObject man page for more info)..

 

Example:

 

// MEL

$node = "fumeFXShape1";

// prepare objects and data

fumeFXcmd - clearObjectList $node;

if ( !`fumeFXcmd - setObject "smoke" $node` )

error "Smoke channel is not allocated!";

int $nx = `fumeFXcmd - getnx $node`;

int $ny = `fumeFXcmd - getny $node`;

int $nz = `fumeFXcmd - getnz $node`;

 

// set smoke value at center of the grid to 2

ffxDynaSetChannelCmd - function "si" 0 - parami1 ($nx*$ny*$nz/2) - valued1 2;

// set smoke value at top center voxel to 3.14

ffxDynaSetChannelCmd - function "sv" 0 - parami3 ($nx/2) ($ny/2) $nz - valued1 3.14;

// set smoke value at voxel containing point [ - 12.3, 73.2, 18.5] in object coordinates to 0.5

ffxDynaSetChannelCmd - function "sl" 0 - paramd3 - 12.3 73.2 18.5 - valued1 0.5;

if ( !`fumeFXcmd - setObject "velo" $node` )

error "Velocity channel is not allocated!";

// set velocity value at voxel containing point [41.0, 13.3, 2.2] in world coordinates to [1,1.5, - 3]

ffxDynaSetChannelCmd - function "vw" 0 - paramd3 41.0 13.3 2.2 - valued3 1 1.5 - 3;

 

 

Block wise procedures

 

Block wise procedures enable you to access blocks of voxels at the time.

 

fumeFXcmd - setFieldValues <string>field <string>data

- useIndexRange <int>start <int>end

- useVoxelRange <int>startX <int>startY <int>startZ <int>endX <int>endY <int>endZ

- useObjectRange <float>startX <float>startY <float>startZ <float>endX <float>endY <float>endZ

- useWorldRange <float>startX <float>startY <float>startZ <float>endX <float>endY <float>endZ

- addValue

- multiplyValue fume;

fumeFXcmd( fume, setFieldValues=[<string>field, <string>data],

useIndexRange=[<int>start, <int>end],

useVoxelRange=[<int>startX, <int>startY, <int>startZ, <int>endX, <int>endY, <int>endZ],

useObjectRange=[<float>startX, <float>startY, <float>startZ, <float>endX, <float>endY <float>endZ],

useWorldRange=[<float>startX, <float>startY, <float>startZ, <float>endX, <float>endY, <float>endZ],

addValue=True,

multiplyValue=True)

Set array of voxel channel values. setFieldValues flag accepts following values for first argument:

- "smoke"

- "fuel"

- "temp"

- "velo"

- "color"

Second argument is string containing values which are to be set to channel. String contains list of numbers (floats or ints) in decimal form separated by spaces (or comma followed by space ???, ???). List may be preceded by '[' and followed by ']'. Simplest way to create such string is to keep all data in a list and than call python str procedure (with list as the argument) to generate string. However, that's not the fastest way; you may preallocate storage for list, and then call join procedure to generate string (see example).

When assigning velocity or color channels, note that list of numbers (contained in the string) should be three times longer (as it contains XYZ or RGB values).

 

Optional flags enable you to define block of voxels for which you want channel data. If no optional flags are given, procedure returns channel values for entire grid.

Color values are RGB float values ranging from 0.0 to 1.0.

 

You can use addValue flag to indicate that data passed as second argument (to setFieldValues flag) should be added to the channel. You can also use multiplyValue flag to indicate that data passed as second argument (to setFieldValues flag) should be interpreted as multiplicators of current channel values. In that case, list of numbers should not be three times longer for velocity and color channels, as you are multiplying all three values with the same multiplier.

 

Returns False on error.

 

Example:

 

# Python

import maya.cmds as cmds

import math

nodeName = 'fumeFXShape1'

 

# prepare objects and data

nx = cmds.fumeFXcmd ( nodeName, getnx=True )

ny = cmds.fumeFXcmd ( nodeName, getny=True )

nz = cmds.fumeFXcmd ( nodeName, getnz=True )

 

''' set smoke channel, bounded in local space, based on the distance from point [30, 50, 40] '''

 

coords_w = cmds.fumeFXcmd ( nodeName, getFieldCoords='world', useObjectRange=[ 10, 40, 20, 50, 60, 40] )

if coords_w != None:

coords_w_len = len(coords_w) / 3 # get number of voxels in bounded region

s = [None] * coords_w_len # preallocate string storage

for i in xrange(coords_w_len):

xi = (30 - coords_w[i*3])

yi = (50 - coords_w[i*3+1])

zi = (40 - coords_w[i*3+2])

di = 10 / (math.sqrt( xi*xi+yi*yi+zi*zi )+0.01)

s[i] = str(di) # use python str procedure to turn numbers into strings

del coords_w

# create string use join procedure and use it to transfer data to FumeFX

cmds.fumeFXcmd(nodeName, setFieldValues=['smoke', ' '.join(s)], useObjectRange=[10, 40, 20, 50, 60, 40])

del s

 

''' set color based on velocity '''

 

vel = cmds.fumeFXcmd ( nodeName, getFieldValues='velo' )

if vel != None:

vel_len = len(vel) / 3 # get number of voxels

c = [None] * len(vel) # preallocate string storage

maxVel = 3 # maximum velocity in grid

for i in xrange(vel_len):

dist_cm = math.sqrt( vel[3*i]**2 + vel[3*i+1]**2 + vel[3*i+2]**2 )

if dist_cm > maxVel:

dist_cm = maxVel

dist_cm /= maxVel

c[3*i] = str(dist_cm)

sm = 1 - dist_cm

c[3*i+1] = str(sm*0.06)

c[3*i+2] = str(sm*0.2)

del vel

# create string use join procedure and use it to transfer data to FumeFX

cmds.fumeFXcmd ( nodeName, setFieldValues=[ 'color', ' '.join(c) ] )

del c

 

 

 

More Channel Functions

You can fill the entire channel with a given value using the following functions:

 

fumeFXcmd - fillSmoke <float>value fume;

fumeFXcmd( fume, fillSmoke=<float>value)

Set all values in smoke channel to value.

fumeFXcmd - fillFuel <float>value fume;

fumeFXcmd( fume, fillFuel=<float>value)

Set all values in fuel channel to value.

fumeFXcmd - fillTemp <float>value fume;

fumeFXcmd( fume, fillTemp=<float>value)

Set all values in temperature channel to value.

fumeFXcmd - fillVel <float>valueX <float>valueY <float>valueZ fume;

fumeFXcmd( fume, fillVel=[<float>valueX <float>valueY <float>valueZ])

Set all values in velocity channel to value.

fumeFXcmd - fillCol <float>valueR <float>valueG <float>valueB fume;

fumeFXcmd( fume, fillCol=[<float>valueR <float>valueG <float>valueB])

Set all values in color channel to value.

 

 

Switching Between Coordinates

If you want to make modifications to FumeFX voxels, you will most often run loops in voxel space or index range.  However, you may need to do some calculations in local or world space for some modifications.  For this and similar cases, converter functions exist between various coordinate spaces that FumeFX uses.

 

Element wise procedures

 

Coordinate switching element wise procedures are part of ffxDynaGetChannelCmd command.

 

 

Block wise procedures

 

Block wise procedures enable you to convert blocks of points with single call.

 

fumeFXcmd - getFieldCoords <string>field

- useIndexRange <int>start <int>end

- useVoxelRange <int>startX <int>startY <int>startZ <int>endX <int>endY <int>endZ

- useObjectRange <float>startX <float>startY <float>startZ <float>endX <float>endY <float>endZ

- useWorldRange <float>startX <float>startY <float>startZ <float>endX <float>endY <float>endZ fume;

fumeFXcmd( fume, getFieldCoords=<string>field,

useIndexRange=[<int>start, <int>end],

useVoxelRange=[<int>startX, <int>startY, <int>startZ, <int>endX, <int>endY, <int>endZ],

useObjectRange=[<float>startX, <float>startY, <float>startZ, <float>endX, <float>endY <float>endZ],

useWorldRange=[<float>startX, <float>startY, <float>startZ, <float>endX, <float>endY, <float>endZ])

Get array of transformed coordinates. getFieldCoords flag accepts following values:

- "index"

- "voxel"

- "object"

- "world"

These values signify transform coordinates in which result points will be given.

 

Optional flags enable you to define block of voxels for which you want channel data. If no optional flags are given, procedure returns transformed coordinates of the entire grid.

 

Returns array of integers in case of useIndexRange flag, array of integers (three times longer than number of voxels) in case of useVoxelRange flag, and array of floats (three times longer than number of voxels) in case of useObjectRange and useWorldRange flags.

 

Example:

 

# Python

import maya.cmds as cmds

nodeName = 'fumeFXShape1'

# * * *

 

# get world coordinates of all voxels bounded by points [30, 50, 60] and [70,80,90] in object coordinates

world_coords = cmds.fumeFXcmd ( nodeName, getFieldCoords='world', useObjectRange=[ 30, 50, 60, 70, 80, 90] )

 

# get voxel coordinates of first hundered points

voxel_coords = cmds.fumeFXcmd ( nodeName, getFieldCoords='voxel', useIndexRange=[ 0, 99] )

 

 

 

Utility Procedures

Here are some additional script procedures exposed by FumeFX:

 

fumeFXcmd - printToStatus <string>message fume;

fumeFXcmd( fume, printToStatus=<string>message)

This prints message to FumeFX status window during simulation.

fumeFXcmd - holdWindow fume;

fumeFXcmd( fume, holdWindow=True)

If this function is called during simulation, then after the simulation has stopped or cancelled, the simulation window will stay open, regardless of Hold Window checkbox selection.

fumeFXcmd - ffxSilent <bool> fume;

fumeFXcmd( fume, ffxSilent=<bool>)

When turned on/True no message box will show up (like Stop/Continue etc.).

fumeFXcmd - setObject <string>channel fume;

fumeFXcmd( fume, setObject=<string>channel)

Used in combination with element wise access procedures. This procedure should be called prior calling ffxDynaGetChannelCmd or ffxDynaSetChannelCmd. The role of this call is to register node and check whether channel is available. Channel should be one of the following:

- smoke

- fuel

- temp

- velo

- color

- coords

Element wise procedures (ffxDynaGetChannelCmd or ffxDynaSetChannelCmd) accept object index as second argument. If there are multiple objects and multiple channels, first object call counts.

 

// MEL

fumeFXcmd - setObject "smoke"  "fumeFXShape1";

fumeFXcmd - setObject "temp"   "fumeFXShape1";

fumeFXcmd - setObject "fuel"   "fumeFXShape2";

fumeFXcmd - setObject "coords" "fumeFXShape1";

fumeFXcmd - setObject "smoke"  "fumeFXShape2";

fumeFXcmd - setObject "color"  "fumeFXShape2";

 

// now ???fumeFXShape1??? can be accessed by index 0 and ???fumeFXShape2??? by index 1

 

 

Prior first call, it is recommended to call clearObjectList, so object list can be cleared.

 

Returns true on success, false on failure.

fumeFXcmd - clearObjectList fume;

fumeFXcmd( fume, clearObjectList=True)

Clears object list - deregisters objects used for element wise access.

fumeFXcmd - getNumVoxels fume;

fumeFXcmd( fume, getNumVoxels=True)

Returns total number of voxels in the grid.

fumeFXcmd - getnx fume;

fumeFXcmd( fume, getnx=True)

Returns number of voxels in first voxel dimension.

fumeFXcmd - getny fume;

fumeFXcmd( fume, getny=True)

Returns number of voxels in second voxel dimension.

fumeFXcmd - getnz fume;

fumeFXcmd( fume, getnz=True)

Returns number of voxels in third voxel dimension.

fumeFXcmd - getSubStep fume;

fumeFXcmd( fume, getSubStep=True)

Returns current substep.

fumeFXcmd - getFrame <int>mode fume;

fumeFXcmd( fume, getFrame=<int>mode)

Returns current frame depending on the mode:

0 - return scene time

1 - return simulation frame

2 - return FumeFX playback time

fumeFXcmd - forceFieldsRedraw fume;

fumeFXcmd( fume, forceFieldsRedraw=True)

This is DEBUG ONLY tool. Writing scripts can be a difficult task. Especially if you have limited feedback to what you're doing. Running scripts during simulation can be confusing, as a lot is going on during each simulation step; fuel is burned, field are advected, forces are applied. All that can obstruct script writers from observing the actual effect their script has.

You can manipulate FumeFX channels directly (without simulating), but you might need to save caches to view the result.

Finally, you can use ffx_mel_PostLoad/postLoad callback, but that's still inconvenient.

 

forceFieldsRedraw flag enables you to view effect script has when executing it from Maya Script Window. It forces FumeFX to redraw fields and show you how are they changed after your script has been executed.