Внешние данные в партикловых экспрешенах
В качестве первого поста в блоге опишу методы оптимизации довольно частой задачи в партикловых экспрешенах – использование в них внешних значений.
Простой пример: производить некое действие над частицей в зависимости от ее дистанции до определенного объекта, допустим, менять цвет при приближении к анимированному локатору:
Первое что приходит на ум – в runtime expression попросту спрашивать позицию локатора в мировом пространстве командой pointPosition:
vector $wPos = `pointPosition -w locator1.rotatePivot`;
Но таким образом эта команда будет исполняться каждой частицей, возвращая одни и те же данные в пределах одного фрейма для каждой. В тестовой сцене с 5000 частиц скорость симуляции примерно 10 fps.
Естественное желание – вычислять мировые координаты локатора лишь один раз за фрейм и использовать для всех частиц. Вычисление можно возложить на ноду pointMatrixMult:
Остается только брать с нее значения в экспрешене:
vector $wPos = `getAttr pointMatrixMult1.output`;
Скорость симуляции в той же тестовой сцене – около 12 fps.
Не намного лучше – каждая частица снова исполняет команду, в данном случае getAttr.
Правильным же решением данной задачи будет сделать коннект атрибутов, которые нужно опрашивать, к particleShape и не пользоваться никакими командами.
Есть пара вариантов как это можно сделать:
1. Создать на particleShape три float атрибута или один vector, куда приконнектить выход pointMatrixMult (на картинке и float’ы и vector одновременно):
и в случае векторного 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 с этим сетапом – зеленый цвет смещается в сторону локатора (все тесты выше были произведены исключительно на введение значений позиции в партикловый экспрешен, т.е. без калькуляции дистанции и окрашивания частиц – поэтому скорость симуляции в сцене ниже).
Собственно, это все что хотел по данному поводу написать 🙂 Надеюсь кому-то это оказалось полезным и натолкнуло на новые мысли и идеи – не мешкайте поделиться ими 🙂
In: FX · Tagged with: expression, maya, particle attribute, particles, perfomance, pointMatrixMult, pointPosition, runtimeBeforeDynamics, worldPosition
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!
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.
on 19 January 2010 at 2:20
Permalink
very very informative to me.
Thanks for ur share!