Возможностям скрипт-контроллеров пою я песню

В этом разделе я позволю себе не переводить хелп по MAXScript, а поделиться с читателем некоторыми моими мыслями о скрипт-контроллерах и привести в доказательство несколько простых примеров (два моих, и один хелпа). Итак, скрипт-контроллеры это невероятно мощная штука, очень полезная и удобная, лично я вообще считаю, что только с их помощью можно создать в 3ds max действительно "крутую" анимацию. Впрочем я также считаю, что без знаний MAXScript сложную анимацию не стоит и начинать. Есть мнение, что максе плохая анимация по сравнению с другими пакетами - это неправда, просто те, кто так заявляет, не знают и даже не представляют себе возможностей MAXScript. В частности скрипт-контроллеры гораздо более универсальны по сравнению с обычно используемыми в сложной анимации инструментами: Wire, Reaction Manager, Expression controller, которые далеко не во всех случаях могут дать нужный эффект и весьма сложны и трудоемки в использовании. Скрипт-контроллеры более универсальны, просты, удобны, их проще применять и редактировать. Кроме того, они обладают совершенно потрясающими преимуществами, за что я их в принципе уважаю и прославляю: в них можно использовать все возможности MAXScript - циклы, функции, доступ к объектам по их именам и переменным. Что угодно, любое свойство любого объекта может участвовать в вычислении выражения скрипт-контроллера: вершины сетки, значения параметров объекта в произвольном кадре или наоборот любое другое неанимируемое свойство объекта (которые кстати нельзя использовать в контроллерах выражения - Expression controller). Также можно использовать глобальные переменные MAXScript для взаимодействия с другими контроллерами и скриптами.

Смысл действия скрипт-контроллера в следующем - скрипт выполняется и на выходе, т.е. своей последней строчкой должен выдать некое значение, удовлетворяющее типу контроллера. Например, если скрипт-контроллер наложен на поворот (rotation) объекта, то результатом работы скрипта должно быть значение поворота - кватернион (quat). Аналогично для контроллера положения (position) или контроллера масштаба (scale) результатом должен быть вектор, для контроллера трансформации (transform) - матрица, для контроллера вещественного числа (float) - вещественное число. Вообщем вот список всех возможных скрипт-контроллеров:

Float Script - float controller
Position Script - position Point3 controller
Point3 Script - Point3 controller
Rotation Script - rotation Quaternion controller
Scale Script - scale Point3 controller
Transform Script - matrix3 PRS controller

Свойства скрипт-контроллеров

<script_controller>.script String default: varies
Позволяет программно задавать и получать текст скрипта внутри контроллера. Значение параметра default: различно в зависимости от типа скрипт-контроллера.
Пример:
$Sphere01.position.controller=position_script()
$Sphere01.position.controller.script = "-$Box01.pos"
 
<script_controller>.ThrowOnError Bool default:true
Контролирует обработку ошибки, если таковая возникнет при расчете выражения скрипт-контроллера. Свойство доступно, начиная с 8-ой версии 3ds Max.


Пример из хелпа: использование контроллера Transform Script

Создайте три объекта-точки: Point01, Point02, Point03 и объект-плоскость Plane.
Откройте вкладку Motion, выделите трек Transform и назначьте ему контроллер Transform Script и введите в поле EXpression следующий скрипт:

dependsOn $Point01.pos.controller --ОБНОВЛЯТЬ ПРИ ДВИЖЕНИИ Point01
dependsOn $Point02.pos.controller --ОБНОВЛЯТЬ ПРИ ДВИЖЕНИИ Point02
dependsOn $Point03.pos.controller --ОБНОВЛЯТЬ ПРИ ДВИЖЕНИИ Point03

p1 = $Point01.pos --ПОЗИЦИЯ Point01
p2 = $Point02.pos --ПОЗИЦИЯ Point02
p3 = $Point03.pos --ПОЗИЦИЯ Point03

v1 = normalize (p2-p1) --ВЕКТОР ОТ Point01 ДО Point02
v2 = normalize (p3-p1) --ВЕКТОР ОТ Point01 ДО Point03
nv1 = cross v1 v2 --ВЕКТОРНОЕ ПРОИЗВЕДЕНИЕ (cross product), ВЕКТОР-НОРМАЛЬ К ПЛОСКОСТИ
nv2 = cross nv1 v1 --ВЕКТОРНОЕ ПРОИЗВЕДЕНИЕ НОРМАЛИ И ВЕКТОРА  v1

--ВОЗВРАЩАЕМ КАК РЕЗУЛЬТАТ СКРИПТ-КОНТРОЛЛЕРА МАТРИЦУ ИЗ ТРЕХ ВЕКТОРОВ,
--ИСПОЛЬЗУЯ В КАЧЕСТВЕ ЦЕНТРА СИСТЕМЫ КООРДИНАТ ТОЧКУ МЕЖДУ ОБЪЕКТАМИ Point
matrix3 v1 nv2 nv1 ((p1+p2+p3)/3)

Потом нажмите кнопку Evaluate и подвигайте объекты-точки.


Следующие примеры моего собственного изготовления, все создается с нуля, функция генерирует скрипт. Объект, на который назначается скрипт, получается ведомым, т.е. управляемым другим объектом или объектами. Запускайте скрипты и двигайте управляющие объекты. Ведомые будут меняться.

Пример зеркального перемещения объекта

После запуска скрипта двигайте и масштабируйте маленькую сферу.

fn PosScaleScript obj = (
            "dependsOn "+ "$'"+obj.name+"'.controller\n" +
            "f = $'"+obj.name+"'.scale.x"+"\n" +
            "p0 = $'"+obj.name+"'.pos"+"\n" +
            "-p0*f"
            )
           
b=sphere pos: [20,20, 0] radius: 5
s=sphere pos: [-20, -20, 0] radius: 10
           
s.pos.controller=position_script ()
s.pos.controller.script=PosScaleScript b
           

Пример назначения контроллера на режущую плоскость модификатора Slice

После запуска скрипта подвигайте любой из созданных объектов.

fn SecScript obj p = (
"dependsOn "+ "$"+obj.name+".pos.controller\n" +
"dependsOn "+ "$"+p.name+".pos.controller\n" +
"p1 = "+"$"+p.name+".pos\n" +
"p0 = "+"$"+obj.name+".pos\n" +
"v1 = normalize (p1-p0)\n" +
"m=matrixFromNormal v1\n" +
"translate m ((p1-p0)/2.0)\n" +
"m"
)

s=Geosphere pos: [0,0,0] segs: 6 radius: 10 wireColor: (color 255 0 0)
p=point pos: [-5, -5, 5] size: 5 centermarker:false axistripod:false cross:true box:true wireColor:[255,255,0]

mSlice = sliceModifier slice_type:2 name: "Slicer"
addModifier s mSlice
addModifier s (cap_holes())

s.modifiers[#Slicer].Slice_Plane.controller=transform_script()
s.modifiers[#Slicer].Slice_Plane.controller.script=SecScript s p
select p