External Values in Particle Expressions

As a first post in this blog I’ll describe optimization methods of pretty common task in particle expressions – using external values in them.

A simple example: do something with a particle based on it’s distance from specific  object, let’s say, change color close to animated locator:

Particles are colored based on distance from locator

Particles are colored based on distance from locator

The first thing that comes to mind is to simply use pointPosition command to get position of the locator in world space in runtime expression:

vector $wPos = `pointPosition -w locator1.rotatePivot`;

But that way this command would be executed by each particle, returning the same values per frame for each one. In test scene with 5000 particles the speed of simulation is about 10 fps.

Of course the thing we want is to calculate world position of the locator just once per frame and use it for all particles. Calculation could be handled by pointMatrixMult node:

pointMatrixMult generates locator's coordinates in world space

pointMatrixMult generates locator's coordinates in world space

The only thing left is to get it’s values in expression:

vector $wPos = `getAttr pointMatrixMult1.output`;

Speed of the simulation in the same scene is about 12 fps.

Not that much better – each particles executes a command again, getAttr in this case.

The proper solution of this task is to make a connection of the attributes we want to use to particleShape and not to use any commands.

There’re a couple of ways to accomplish that:

1. To create three float attributes or one vector attribute for particleShape and connect output of pointMatrixMult to it (picture shows both floats and vector):

Custom attributes on particleShape connected to pointMatrixMult

Custom attributes on particleShape connected to pointMatrixMult

and in case of vector vec use:

vector $wPos = <<vecX, vecY, vecZ>>;

or for three floats fltX, fltY, fltZ:

vector $wPos = <<fltX, fltY, fltZ>>;

2. To make a connection from expression directly to pointMatrixMult node:

vector $wPos = <<pointMatrixMult1.outputX, pointMatrixMult1.outputY, pointMatrixMult1.outputZ>>;

Test simulation is way faster – it clamps at 60 fps, so I’ve increased particle count to 100000, and the speed for all of these setups stays the same – around 14 fps.

If you need to get a specific attribute – second setup is better (no need to create custom attributes for particleShape), but if you need to precalculate somehow these values – first setup with standard expression for the attribute is more useful (of course you can connect directly to output[#] of expression node, but the process of such setup becomes pretty weird in this case).

Anyway, there’s more perverse but faster method. Concerning the speed it’s as fast as just assigning variable a plain value in particle expression, something like:

vector $wPos = <<0, 0, 0>>;

Actually, this method is doing just that – simple non-particle expression gets all the values we need and inserts them into particle expression as a variable value. The code below takes existing runtime before dynamics expression, replaces the values of the vector variable and reapplies it back to particleShape:

float $wPos[] = `pointPosition -w locator1.rotatePivot`;

string $expr = `dynExpression -q -s -rbd particleShape1`;

string $exprLines[] = {};
tokenize( $expr, ";", $exprLines );

string $newExpr = "";
for( $line in $exprLines ) {
	$newExpr += `substitute "vector $wPos = <<.*>>" $line ( "vector $wPos = <<"
		+ $wPos[0] + ", " + $wPos[1] + ", " + $wPos[2] + ">>" )`;
	$newExpr += ";";
}

dynExpression -s $newExpr -rbd particleShape1;

And this method is as fast as you can get, I think – 24 fps for 100000 particles. I’m adding Maya2008 scene with this setup – green color shifts towards locator (all test above were made only just for inputting position values into particle expression, i.d. without distance calculation and particles coloring – that’s why the speed of simulation in the scene is lower).

example_scene

And that’s all I wanted to write about it 🙂 I hope it was useful for some of you and inspired some new thoughts and ideas – don’t hesitate to share them 🙂

3 Responses

Subscribe to comments via RSS

  1. Written by Olygraph
    on 29 July 2009 at 19:26
    Permalink

    how do you add the node pointMatrixMult? I understand you can use it with mel, but I can’t find how to add it as a node?

    Thanks, your blog has really usefull info!

  2. Written by Sagroth
    on 29 July 2009 at 19:38
    Permalink

    I don’t think there’s a way to add it from interface, so the only way is to use “createNode pointMatrixMult;” command.

  3. Written by 3don
    on 19 January 2010 at 2:20
    Permalink

    very very informative to me.
    Thanks for ur share!

Subscribe to comments via RSS

Leave a Reply