Внешние данные в партикловых экспрешенах

В качестве первого поста в блоге опишу методы оптимизации довольно частой задачи в партикловых экспрешенах – использование в них внешних значений.

Простой пример: производить некое действие над частицей в зависимости от ее дистанции до определенного объекта, допустим, менять цвет при приближении к анимированному локатору:

Particles are colored based on distance from locator

Particles are colored based on distance from locator

Первое что приходит на ум – в runtime expression попросту спрашивать позицию локатора в мировом пространстве командой pointPosition:

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

Но таким образом эта команда будет исполняться каждой частицей, возвращая одни и те же данные в пределах одного фрейма для каждой. В тестовой сцене с 5000 частиц скорость симуляции примерно 10 fps.

Естественное желание – вычислять мировые координаты локатора лишь один раз за фрейм и использовать для всех частиц. Вычисление можно возложить на ноду pointMatrixMult:

pointMatrixMult generates locator's coordinates in world space

pointMatrixMult generates locator's coordinates in world space

Остается только брать с нее значения в экспрешене:

vector $wPos = `getAttr pointMatrixMult1.output`;

Скорость симуляции в той же тестовой сцене – около 12 fps.

Не намного лучше – каждая частица снова исполняет команду, в данном случае getAttr.

Правильным же решением данной задачи будет сделать коннект атрибутов, которые нужно опрашивать, к particleShape и не пользоваться никакими командами.

Есть пара вариантов как это можно сделать:

1. Создать на particleShape три float атрибута или один vector, куда приконнектить выход pointMatrixMult (на картинке и float’ы и vector одновременно):

Custom attributes on particleShape connected to pointMatrixMult

Custom attributes on particleShape connected to pointMatrixMult

и в случае векторного vec использовать:

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

или при трех флоатовых fltX, fltY, fltZ:

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

2. Сделать коннект к pointMatrixMult прямо из экспрешена:

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

Тестовая симуляция значительно быстрее – зашкаливает на 60 fps, поэтому пришлось увеличить кол-во частиц до 100000, при которых скорость для всех этих вариантов держится на одинаковой отметке около 14 fps.

Если нужно опросить какой-то конкретный атрибут – удобен второй вариант (не надо возиться с созданием дополнительных атрибутов на particleShape), если же нужно значения как-то вычислить – первый вариант с экспрешеном на атрибутах (можно, конечно, подключиться напрямую к output[#] экспрешен ноды, но в этом случае сетап становится несколько замороченным).

Как бы то ни было, есть более извращенный, но более быстрый способ. По скорости такой же как просто задать переменной конкретное значение в партикловом экспрешене, типа:

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

Собственно, способ в этом и заключается – обычным непартикловым экспрешеном для каждого фрейма получить нужные данные и подставить их в партикловый экспрешен в виде значения переменной. Следующий код берет в каждом фрейме текущий runtime before dynamics экспрешен, заменяет в нем значение вектора и обратно назначает 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;

И этот метод – самый быстрый из возможных, насколько я понимаю – 24 fps при 100000 частиц. Прилагаю сцену под Maya2008 с этим сетапом – зеленый цвет смещается в сторону локатора (все тесты выше были произведены исключительно на введение значений позиции в партикловый экспрешен, т.е. без калькуляции дистанции и окрашивания частиц –  поэтому скорость симуляции в сцене ниже).

example_scene

Собственно, это все что хотел по данному поводу написать 🙂 Надеюсь кому-то это оказалось полезным и натолкнуло на новые мысли и идеи – не мешкайте поделиться ими 🙂

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