MAXScripting FumeFX

 

MAXScript is a powerful 3ds Max language that allows users to customize their interface, automate tasks, or increase functionality. FumeFX's open architecture facilitates the use of this tool, which means you can tailor FumeFX to meet your own needs. Refer to the 3ds Max Reference Guide for general information on how to use this tool.

 

 

Globals

Here is a list of global variables exposed to MXS.

 

ffxSilent - No Message box will show up (like Stop/Continue).

 

 

Adding/Removing objects

Here is a list of all functions exposed by FumeFX Object Source.

 

<integer>NumObjects()

Returns the number of objects.

 

<node>GetObject <integer>index

Returns object.

index - its range goes from 0 to NumObjects()-1

 

<boolean>AddObject <node>node

It will add an object to the list. No duplicates or unsupported objects will be added.

 

<boolean>RemoveObjectByNode <node>node

Removes object based on the node.

 

<boolean>RemoveObjectByIndex <integer>index

Removed object based on the object's index.

 

 

Saving and Loading Presets

Here is a list of all functions exposed by FumeFX.

 

SavePresets <filename>presetFile

This saves all current FumeFX settings to a preset file ???presetFile.fxp??? in default preset folder. The output returns false on error.
If user provides a full path to the preset file (like c:\\mypresets\\explosion.fxp) then the preset file will be saved to the specified folder.

 

LoadPresets <filename>presetFile <rollout_names_array>rollouts

Use this to load all or some of the controls from the preset file ???presetFile.fxp???. The output returns false upon error.

If user provides a full path to the preset file (like c:\\mypresets\\explosion.fxp) then the preset file will be loaded from the specified folder.

 

The Rollouts parameter is an array with some of the following values:

 

all: load all rollouts

 

grid: load all rollouts from Grid Tab

 

sim: load all rollouts from Simulation Tab

 

render: load all rollouts from Render Tab

 

illum: load all rollouts from Illumination Tab

 

grid_dim: load Grid Tab / General Parameters Rollout

 

grid_play: load Grid Tab / Playback Rollout

 

grid_rec: load Grid Tab / Recording Parameters Rollout

 

sim_main: load Simulation Tab / Simulation Rollout

 

sim_smoke: load Simulation Tab / Smoke Rollout

 

sim_fuel: load Simulation Tab / Fuel Rollout

 

sim_temp: load Simulation Tab / Temperature Rollout

 

sim_fm: load Simulation Tab / Fluid Mapping Rollout

 

render_main: load Rendering Tab / Rendering Parameters

 

shader: load Rendering Tab / Shader Rollout

 

Examples:

 

-- have FumeFX01 save its settings to file mypreset.fxp in default presets folder

$FumeFX01.SavePresets ???mypreset1???

 

-- have selected FumeFX object load Render Tab > Render parameters rollup and Simulation Tab > Fuel rollup from file mypreset1.fxd.

$.LoadPresets "mypreset1" #(???render_main???, ???sim_fuel???)

 

-- have FumeFX01 load all rollouts in Grid Tab from file mypreset.fxd.

$FumeFX01.LoadPresets "mypreset" ???grid???

 

 

Adding/Removing objects, lights, sources

<integer>NumSources()

Returns number of sources.

 

<node>GetSource <integer>index

Returns source.

index - its range goes from 0 to NumSources()-1


<boolean> AddSource <node>source

Use this to attach FumeFX Sources to FumeFX. It is equivalent to picking a Source object in the Objects panel of the Floater Window.

 

<boolean> RemoveSource <node>source

Use this to remove Force FumeFX Sources from FumeFX. It is equivalent to removing a Source object in the Objects panel of the Floater Window.

 

<boolean> AddForce <node>force

Use this to attach Force objects like Wind to FumeFX. It is equivalent to picking a Force object in Objects panel of the Floater Window.

 

<boolean> RemoveForce <node> force

Use this to remove Force objects like Wind from FumeFX. It is equivalent to removing a Force object in Objects panel of the Floater Window.

 

<integer> NumObjects()

Returns a number of objects that are currently picked.

 

<maxObject>GetObject <integer>index

Returns object based on index (zero based index).

 

<boolean>AddLight <node>node
Adds a light

 

<boolean>RemoveLight <node>node

Removes light

 

<integer> NumEffectors()

Returns a number of Effectors that are currently picked.

 

<maxObject>GetEffector <integer>index

Returns Effector based on index (zero based index).

 

<integer> NumSpaceWarps()

Returns a number of objects that are currently picked.

 

<maxObject>GetSpaceWarp <integer>index

Returns SpaceWarp based on index (zero based index).

 

 

Shader Access

<maxObject>GetShader()

Returns current shader.

 

<boolean>SetShaderByName <string>name

Sets current shader based on name.

 

<boolean>SetShaderByIndex <integer>index

Sets current shader based on index (zero based).

 

 

Simulation Control

<void>CancelSimulation()

This command will cancel the simulation

 

<void>StopSimulation()

This command will stop the simulation. This means it will finish the current frame and save stop/continue data according to the preferences settings.

 

<void>RunSimulation <integer>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

 

<void>ContinueSimulation <integer>simMode

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

simMode - 0 - Default Simulation

1 - Default Simulation

2 - Wavelet Simulation

 

<boolean>SetInitialStateFile <filename>filename

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

 

<filename>GetInitialStateFile()

Returns Initial State file name.

 

SaveOutput <filename>outputFile

This saves a .fxd type output file; note, you must enter the full file name. Output returns false on error.

 

SaveSim <filename>presetFile

This saves a .fdc type simulation file; note, you must enter full file name. Output returns false on error.

 

<boolean>LoadSim <filename>filename

This will load a .fdc file into the FumeFX.

 

<filename>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

presets - path for presets

defaultpreset - path for the default preset file (Preferences)

scrsim - FumeFX MXS file

 

<boolean>SetPath <filename>path <name array>params

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

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

defaultpreset - path for the default preset file (Preferences)

nocheck - path validity won't be checked.

scrsim - FumeFX MXS file

 

 

This sets output file name. You must enter the path and base file name; the extension is not necessary.


Examples:

$FumeFX01.SetPath "F:\\temp\\FumeFX\\aa"

$FumeFX01.SetPath "F:\\temp\\FumeFX\\aa.fxd"
$FumeFX01.SetPath "F:\\temp\\FumeFX\\aa.fxd" #(???default???, ???nocheck???)

$FumeFX01.SetPath "F:\\temp\\FumeFX\\aa_0000.fxd" #(???default???,???match???)
For #match, if you omit _0000 (or any existing frame number), FumeFX and cache won't be checked for grid dimensions and won't be matched if grid and cache have different sizes.

 

<void>DeleteCaches <string>name

This command will delete all the cache files

Name -default- path for Default Sim. caches

wavelet- path for Wavelet Sim. caches

retimer- path for Retimer Sim. caches

illummap - path for Illumination Map. caches

 

<boolean>ExportRenderingParams <string>name

This will save current frame rendering params to the file.

 

 

Misc. Functions

<int>GetBBox <point3>&dim0 <point3>&dim1

This command will return the cache number that is currently loaded and FumeFX bounding box in local coordinates. The return number of -99999 could indicate that there was no cache loaded in memory at the time this function was called.
Returned values in dim0 and dim1 are corners of the bounding box.

Example:
min=[0,0,0]

max=[0,0,0]

$.GetBBox &min &max

 

<int>GetFireInfo<float>&min <float>&max <float>&avg

<int>GetSmokeInfo<float>&min <float>&max <float>&avg
<int>GetTempInfo<float>&min <float>&max <float>&avg
<int>GetVelInfo<float>&min <float>&max <float>&avg

This command will return the cache number that is currently loaded. The return number of

-99999 could indicate that there was no cache loaded in memory at the time this function was called or that channel was not present inside the cache.

min - returns the minimum channel value inside the grid

min - returns the maximum channel value inside the grid

avg - returns the average channel value inside the grid (empty voxels are excluded).
After the simulation is finished FumeFX will load channels depending on the viewport or requirements. To force channel to be loaded you should enable its display inside the viewport.

 

 

FumeFX MAXScript Functions for Accessing the Simulation

By learning to use FumeFX functions created for MAXScript, 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.

 

In this version of FumeFX, MAXScript cannot be called from the Listener, Macro Scripts, or in any other way except from within FumeFX while the simulation is running or the output is being loaded. Preparation of the scripts takes place in the General panel of the Floater Window. You can access this by clicking the Edit Script button in the MAXScript rollout.

 

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:

fn PostObjects = (

for i in 0 to (nx - 1) do

for j in 0 to (ny - 1) do

for k in 0 to (nz - 1) do(

val=k/(nz as float)

     SetSmoke i j k val

)

)

 

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 through all voxels in the adaptive grid (nx, ny and nz are global variables provided by FumeFX) and initialize the Smoke channel with a vertical gradient going from 0 to 1 over the local Z-axis. Channel is set using voxel coordinates.

 

 

MAXScript in FumeFX Simulation

How it works:

When you click Edit Script in the Simulation group, you will see a template in which to write your scripts. In it there are certain MAXScript functions 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.

 

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.

 

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

 

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.

 

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.

 

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???

 

PostAdvection: 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.

 

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.

 

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.

 

 

Skipping FumeFX Simulation Phases

If you want to skip certain FumeFX simulation phases completely, uncomment in the template, or write the following statements on the global level of the script:

skipForces = true

skipAdvectFields = true

skipAdvectVels = true

skipPressure = true

skipBurn = true

 

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.

 

So, what can you do within these functions? Basically, you can get and set values for the main channels: Smoke, Fuel, Temperature and Velocity. You can also stop or cancel simulation and write messages to the FumeFX status window.

 

 

Simulation Control Functions

ffxPrintToStatus <string>message

This prints message to FumeFX status window during simulation.

 

ffxStopSimulation()

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

 

ffxCancelSimulation()

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

 

ffxHoldWindowOnce()

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.

 

 

Get Channel Functions

Smoke is used in this example; however, all other channels are analogous. The ways to get Smoke values are:

 

GetSmoke <integer>i <integer>j <integer>k

In this function, i, j, and k respectively represent the X, Y, and Z-axis coordinates in an adaptive grid. Voxel coordinates can range from 0 to nx-1 for i, 0 to ny-1 for j, and 0 to nz-1 for k. So, to get the smoke value in first voxel you would write

GetSmoke 0 0 0

 

Or, to get it from the top center voxel you would write:

GetSmoke (nx/2) (ny/2) (nz)

 

GetSmokeByIndex <integer>index

This is slightly faster than the form GetSmoke i j k. It uses only one parameter, voxel index, which is computed (i*ny + j)*nz + k.

To get the average value of smoke

average = 0.0

for ind in 0 to (voxels-1) do (average += GetSmokeByIndex ind)

average /= voxels

 

GetSmokeLocal <point3>lpt

Here lpt is a point in a FumeFX object or local space. Unless the pivot is moved, the center of that coordinate system is the bottom center point of the FumeFX object. FumeFX dimensions are exposed through FumeFX nodes: Width, Length, and Height.

GetSmokeLocal [10.0, 10.0, $FumeFX01.Heigth/2]

 

GetSmokeWorld <point3>wpt <matrix3>FumeFXt

Here wpt is a position in world coordinates. You must also provide a FumeFX transformation matrix.

 

To get Smoke density at some object's position

wpt = $sensor01.position

tm = $FumeFX01.transform

if ((GetSmokeWorld wpt tm) > threshold) then myfunction()

 

These functions will return undefined if you ask for non-existing coordinates or coordinates outside of the grid. They will also return undefined if the channel has not been allocated - for example GetFuel() if Simulate Fire has been turned off in the Simulation tab.

 

A complete list of Get functions:

 

float GetSmoke

 

float GetSmokeByIndex

 

float GetSmokeLocal

 

float GetSmokeWorld

 

float GetTemp

 

float GetTempByIndex

 

float GetTempLocal

 

float GetTempWorld

 

float GetOxy

 

float GetOxyByIndex

 

float GetOxyLocal

 

float GetOxyWorld

 

float GetFuel

 

float GetFuelByIndex

 

float GetFuelLocal

 

float GetFuelWorld

 

point3 GetVel

 

point3 GetVelByIndex

 

point3 GetVelLocal

 

point3 GetVelWorld

 

Usage of functions:

 

GetChannel i j k

 

GetChannelByIndex index

 

GetChannelLocal lpt

 

GetChannelWorld wpt TM

 

Index and i,j,k coordinates must be passed as integers.

 

 

Set Channel Functions

To set channel values, functions are provided that are analogous to the Get functions. They only have one additional parameter - value to set. Input ranges are not checked - so accuracy is important. The output can return true or false even if the value was, for some reason, not set.

These functions set value at one voxel only - the voxel that the point belongs to.

 

SetSmoke <integer>i <integer>j <integer>k <float>value

This uses adaptive grid voxel coordinates.

 

SetSmokeByIndex <integer>index <float>value

This uses voxel index.

 

SetSmokeLocal <point3>lpt <float>value

This uses FumeFX local coordinates.

 

SetSmokeWorld <point3>wpt <matrix3>FumeFXtm <float>value

This uses world coordinates.

 

A complete list of Set functions:

 

float SetSmoke

 

float SetSmokeByIndex

 

float SetSmokeLocal

 

float SetSmokeWorld

 

float SetTemp

 

float SetTempByIndex

 

float SetTempLocal

 

float SetTempWorld

 

float SetOxy

 

float SetOxyByIndex

 

float SetOxyLocal

 

float SetOxyWorld

 

float SetFuel

 

float SetFuelByIndex

 

float SetFuelLocal

 

float SetFuelWorld

 

point3 SetVel

 

point3 SetVelByIndex

 

point3 SetVelLocal

 

point3 SetVelWorld

 

Usage of functions:

 

SetChannel i j k value

 

SetChannelByIndex index value

 

SetChannelLocal lpt value

 

SetChannelWorld wpt TM value

 

Smoke, Fuel and Temperature are float channels, and Velocity is a point3 channel. Remember to set the point3 channels with the point3 values, for example:

 

SetVelByIndex index [x,y,z]

 

 

More Channel Functions

There are also functions for 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.

 

Note: Vorticity strengths above 1 may, in rare cases, make the simulation unstable.

 

To add Turbulence, you can use:

 

AddTurb <integer>i <integer>j <integer>k <float>value

 

AddTurbByIndex <integer>index <float>value

 

AddVort functions can only be used during Vorticity callback.

 

AddVort <integer>i <integer>j <integer>k <float>value

 

AddVortByIndex <integer>index <float>value

 

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

 

FillSmoke <float>value

 

FillFuel <float>value

 

FillTemp <float>value

 

FillVel <point3>value

 

 

MAXScript after Loading Output

It is possible to post-process FumeFX output files at the time of loading. Here, for example, you can change the displayed result or the result used by the particles without affecting the simulation. Appropriate callback is called PostLoad.

 

Example: To set smoke to any given minimum value throughout the entire grid, achieving a fog-like effect, enter the following script.

 

fn PostLoad = (

sm = 1.0 -- desired minimum smoke value

for i in 0 to (voxels-1) do

(

s = GetSmokeByIndex i

if (s < sm) then ( SetSmokeByIndex i sm )

)

)

 

 

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.

 

List of functions:

 

<integer> ffxVoxelPtToIndex <point3>vpt

 

<point3> ffxVoxelPtToLocal <point3>vpt

 

<point3> ffxVoxelPtToWorld <point3>vpt

 

 

<point3> ffxIndexToVoxel <integer>ind

 

<point3> ffxIndexToLocal <integer>ind

 

<point3> ffxIndexToWorld <integer>ind

 

 

<integer> ffxLocalPtToIndex <point3>lpt

 

<point3> ffxLocalPtToVoxel <point3>lpt

 

<point3> ffxLocalPtToWorld <point3>lpt

 

 

<integer> ffxWorldPtToIndex <point3>wpt

 

<point3> ffxWorldPtToVoxel <point3>wpt

 

<point3> ffxWorldPtToLocal <point3>wpt

 

 

VoxelPtTo??? functions take point3 as argument, in adaptive grid coordinates, ranging [0.,0.,0.] - [nx, ny, nz].

 

IndexTo??? functions take integer as argument, ranging from 0 to (voxels-1).

 

LocalPtTo??? functions take point3 as argument, in FumeFX local coordinates, ranging from [-Width/2, -Length/2, 0.] - [Width/2, Length/2, Height] for values inside the FumeFX grid.

 

WorldPtTo??? functions take point3 as argument, in world coordinates.

 

IndexTo??? functions must get valid index or they return undefined, other functions will convert between spaces regardless of whether the point is within FumeFX grid or not.

 

???ToVoxel functions return point3 ranging from 0 to [0.,0.,0.] - [nx, ny, nz].

 

???ToIndex functions return integer ranging from 0 to (voxels-1).

 

???ToLocal functions return point3 ranging from 0 to [-Width/2, -Length/2, 0.] - [Width/2, Length/2, Height] for values inside FumeFX grid.

 

???ToWorld functions return point3 in world space.

 

 

Various Issues

FumeFX will execute MAXScript commands in a single thread, but the usual simulation phases still execute in multiple threads. So, if you do heavy scripting you can expect some slowdowns.

 

If you Get and Set just a few channel values at once, you will not have to be concerned with memory issues. However, should you want to keep a copy of a whole channel in memory as a MAXScript array, you will have to enlarge MAXScript's heap size. To do this, go to Customize -> Preferences -> MaxScript tab -> Memory group -> Initial heap allocation. To copy a float channel with 1 million voxels to MAXScript's array you will need 28MB of MAXScript Heap memory, and for a point3 channel you will need 36MB.

 

If you no longer need such a big array or if you want to overwrite it, do the following:

 

arrayname = #() -- make it an empty array

 

arrayname = undefined -- or undefine it completely

 

gc light:true -- wipe it from memory

 

The statement ???gc??? invokes the MAXScript garbage collector. Otherwise, if the array takes most of the MAXScript heap, just writing to the same array twice may take an incredibly long time. See the ???Memory Allocation and Garbage Collection??? and ???Manual Garbage Collection??? in the MAXScript User Reference for more detail.

 

 

Notes

You have to provide valid values to FumeFX when you set them.

For Fuel, ranges are -100 to 100. Set negative values to have fuel in non-burning state, or set positive values to have already burning fuel.

 

If you want to use the time slider's global variable in FumeFX scripts, add one frame to it. FumeFX sets the time slider when it has finished calculating a frame. For example, when calculation of frame 5 is in progress, the slider time global variable will still be at frame 4.