Итак, время и место. Вся динамика рассчитывается при помощи специального функционального узла - солвера (rigid body solver), «решателя», который создается автоматически, как только мы создаем первое твердое тело. И первым делом мы должны дать задание солверу, который носит имя rigidSolver, отслеживать возникновение коллизий.
9. В редакторе атрибутов узла rigidSolver в разделе Rigid SolverStates включим опцию Contact Data.
setAttx rigidSolver.contactData 1; Теперь в процессе работы солвера будут вырабатываться данные о коллизиях твердых тел между собой. Для каждого твердого тела информация о коллизиях носит, естественно, индивидуальный характер и становится доступной через локальные атрибуты каждого твердого тела. Нам понадобятся contactCount и contactPosition - соответственно число и координаты коллизий в данный момент времени. Как только значение атрибута con- tactCount становится отличным от нуля, то это означает наличие коллизий рассматриваемого тела с другим телом (или другими телами). В этом случае в contactPosition (а это массив!) заносятся координаты всех произошедших столкновений.
Но прежде чем вводить в действие механизм обработки коллизий, необходимо создать «искры» -систему частиц, которые будут порождаться в точках соприкосновения куба и плоскости. Часть свойств этой системы частиц мы определим «изнутри» - с помощью начальных выражений (creation expression)
- это будут направление и скорость их движения - а часть, такие как цвет и место возникновения, будем определять «извне» - в теле команды emit.
10 ■ Создаем систему частиц с привычным именем sparkParticles и, как и в предыдущем примере, добавим ей атрибут цвета с опцией per particles:
particle -name sparkParticles;
addAttr -longName "rgbPP" -dataType vectorArray sparkParticlesShape; addAttr -longName "rgbPPO" -datatype vectorArray sparkParticlesShape;
11 ■ Теперь самое время добавить в сцену немного «искр». Откроем Expression Editor и создадим вот такое выражение, которое назовем sparkExpression:
int $i,$j; vector $sparkColor; float $hue;
float ScurrContactPos[3]; int $sparkNum=30; if ( activeRigidBody.contactcount>0 ) for ($i=0; $i< activeRigidBody.contactCount; $i++) {
$currContactPos='getAttr activeRigidBody.contactPosition[$i]';
$hue=rand(l);
$sparkColor=hsv_to_rgb( << $hue, 1, 1 >> ); for ($j=0; $j< $sparkNum; $j++) emit -o sparkParticles
-position ($currContactPos[0]) ($currContactPos[l]) ($currContactPos[2])
-attribute rgbPP -vectorValue ($sparkColor.x) ($sparkColor.y) ($sparkColor.z);
}; Как все выше написанное должно работать? Попробуем разобраться. Выполнение условия (activeRigidBody.contactCount >0) означает, что коллизия произошла. На самом деле, точек контакта кубика и плоскости может быть несколько (кубик может упасть вершиной вниз, а может и целой гранью), и в каждой точке контакта должны появиться «искры». Поэтому дальше - цикл по количеству точек контакта. Для каждой такой точки определяем ее координаты (где произошло столкновение):