Работа с обратной кинематикой

Flash Player 10 и более поздних версий, Adobe AIR 1.5 и более поздних версий, требуется Flash CS4 или более поздних версий

Обратная кинематика (ОК) — это отличная техника для создания реалистичного движения.

ОК позволяет создавать скоординированные движения в пределах цепи связанных между собой частей, образующих каркас ОК, так что эти части правдоподобно двигаются вместе. Части каркаса называются костями и соединениями. На основе конечной точки каркаса ОК вычисляет углы для соединений, необходимые для достижения этой конечной точки.

Вычислять эти углы вручную довольно проблематично. Прелесть этой функции заключается в том, что каркасы можно создавать в интерактивном режиме с помощью Adobe® Flash® Professional. Затем они анимируются с помощью ActionScript. Модуль ОК, включенный в среду разработки Flash Professional, выполняет вычисления, чтобы описать движение каркаса. С помощью кода ActionScript движение можно ограничить определенными параметрами.

В новой версии модуля обратной кинематики для Flash Professional CS5 присутствует поддержка костной пружины, обычно являющаяся атрибутом профессиональных приложений для создания анимации. В совокупности с механизмом физического моделирования эта функция позволяет добиться максимально реалистичного движения. Результат использования этой функции виден как во время выполнения, так и во время разработки.

Для создания каркасов обратной кинематики необходимо иметь лицензию на Flash Professional.

Основы обратной кинематики

Обратная кинематика (ОК) позволяет создавать реалистичную анимацию путем соединения частей так, что они правдоподобно передвигаются относительно друг друга.

Например, с помощью ОК можно переместить ногу в определенное положение путем воспроизведения движений составов ноги, необходимых для перехода в нужную позу. ОК использует систему костей, связанных вместе в структуре, которая называется каркасом ОК. С помощью пакета fl.ik можно создавать анимацию, напоминающую естественные движения. Он позволяет согласованно анимировать несколько каркасов ОК, не требуя знаний по физике, на основе которой построены алгоритмы ОК.

С помощью Flash Professional создайте каркас ОК с вспомогательными костями и соединениями. Затем вы сможете обращаться к классам ОК, чтобы анимировать их во время выполнения.

Подробные инструкции по созданию каркаса ОК см. в разделе «Использование обратной кинематики» в руководстве Использование Flash Professional .

Важные понятия и термины

Ниже приводится список важных терминов, относящихся к этой функции.

Арматура
Кинематическая цепочка, состоящая из костей и соединений, которая используется в компьютерной анимации для симуляции реалистичного движения.

Кость
Несгибаемый сегмент каркаса, аналогичный кости в скелете животного.

Обратная кинематика (ОК)
Процесс определения параметров объекта с гибкими соединениями, называемого кинематической цепочкой или каркасом.

Соединение
Место, в котором соединяются две кости, которое обеспечивает движение костей; аналогично суставу животного.

Механизм физического моделирования
Пакет алгоритмов, связанных с физикой, используемый для обеспечения правдоподобных движений при анимации.

Пружина
Качество кости, которая перемещается и реагирует на движение родительской кости, а затем это движение со временем затухает.

Обзор анимации каркасов ОК

Создав каркас ОК в Flash Professional, используйте классы fl.ik для ограничения его движений, отслеживания событий и анимации во время выполнения.

На следующем рисунке показан фрагмент ролика с именем Wheel. Валом является экземпляр IKArmature с именем Axle . Класс IKMover перемещает каркас синхронно с вращением колеса. Объект IKBone, ikBone2 , в каркасе присоединен к колесу хвостовым соединением.

A.
Wheel

Б.
Axle

В.
ikBone2

Во время выполнения приложения колесо вращается в зависимости от анимационного перехода __motion_Wheel (см. раздел Описание анимации ). Объект IKMover инициирует и контролирует движение вала. На следующем рисунке приводится два снимка кадров каркаса вала, присоединенного к колесу, на разных этапах вращения.

Движение каркаса ОК в двух разных позициях
Во время выполнения следующий код ActionScript:
  • получает информацию о каркасе и его компонентах;

  • создает экземпляр класса IKMover;

  • перемещает вал в соответствии с вращением колеса.

import fl.ik.* 
 
var tree:IKArmature = IKManager.getArmatureByName("Axle"); 
var bone:IKBone = tree.getBoneByName("ikBone2"); 
var endEffector:IKJoint = bone.tailJoint; 
var pos:Point = endEffector.position; 
 
var ik:IKMover = new IKMover(endEffector, pos); 
ik.limitByDistance = true; 
ik.distanceLimit = 0.1; 
ik.limitByIteration = true; 
ik.iterationLimit = 10; 
 
Wheel.addEventListener(Event.ENTER_FRAME, frameFunc); 
 
function frameFunc(event:Event) 
{ 
    if (Wheel != null) 
    { 
        var mat:Matrix = Wheel.transform.matrix; 
        var pt = new Point(90, 0); 
        pt = mat.transformPoint(pt); 
         
        ik.moveTo(pt); 
    } 
}

Для передвижения вала используются следующие классы ОК.

  • IKArmature: описывает каркас, имеет структуру дерева, состоящую из костей и соединений; необходимо создать с помощью Flash. Professional

  • IKManager: класс-контейнер для всех каркасов ОК в данном документе; его необходимо создать с помощью Flash Professional.

  • IKBone: сегмент каркаса ОК.

  • IKJoint: соединение двух костей ОК

  • IKMover: инициирует и контролирует движение ОК каркасов.

Полные и подробные описания этих классов см. в пакете ik .

Получение сведений о каркасе ОК

Во-первых, необходимо объявить переменные для каркаса, костей и соединений, которые образуют части, которые должны передвигаться.

В следующем коде используется метод getArmatureByName() класса IKManager, чтобы присвоить значение каркаса Axle переменной IKArmature с именем tree . Каркас Axle был предварительно создан с помощью Flash Professional.

var tree:IKArmature = IKManager.getArmatureByName("Axle");

Подобным образом следующий код использует метод getBoneByName() класса IKArmature, чтобы присвоить переменной IKBone значение кости ikBone2 .

var bone:IKBone = tree.getBoneByName("ikBone2");

Хвостовое соединение кости ikBone2 является частью каркаса, присоединенного к вращающемуся колесу.

Следующая строка объявляет переменную endEffector и назначает ее свойству tailjoint кости ikBone2 .

var endEffector:IKJoint = home.tailjoint;
Переменная pos является точкой, в которой сохранена текущая позиция соединения endEffector .
var pos:Point = endEffector.position;

В данном примере pos — это позиция соединения в конце вала, где он прикрепляется к колесу. Исходное значение этой переменной получается из свойства position объекта IKJoint.

Создание экземпляра IK Mover и ограничение его движения

Экземпляр класса IKMover передвигает вал.

Следующая строка кода создает объект IKMover с именем ik , передавая его конструктору элемент, который должен двигаться, и начальную точку движения.
var ik:IKMover = new IKMover(endEffector, pos);

Свойства класса IKMover позволяют ограничить движение каркаса. Движение можно ограничить по расстоянию, количество повторов и времени движения.

Для установки этих ограничений служат следующие пары свойств. Пара состоит из логического значения Boolean, которое указывает, ограничено ли движение, и целого числа, определяющего степень ограничения.

Свойство Boolean

Свойство Integer

Ограничение

limitByDistance:Boolean

distanceLimit:int

Задает максимальное расстояние в пикселах, на которое перемещается модуль ОК в пределах каждого повтора.

limitByIteration:Boolean

iterationLimit:int

Задает максимальное число повторений, выполняемых модулем обратной кинематики для каждого движения.

limitByTime:Boolean

timeLimit:int

Задает максимальное время в миллисекундах, выделенное модулю ОК для выполнения движения.

По умолчанию все значения типа Boolean равны false , поэтому движение не ограничено, если вы в явном виде не задали значение типа Boolean равным true . Чтобы ввести ограничение, задайте соответствующему свойству значение true , после чего укажите значение связанного с ним целочисленного свойства. Если задать для ограничения целочисленное значение, не настроив соответствующего свойства Boolean, то ограничение игнорируется. В этом случае модуль ОК продолжает передвигать объект до другого ограничения или до достижения целевой позиции объекта IKMover.

В следующем примере максимальному расстоянию движения каркаса задано значение 0,1 пиксела для каждого повтора. Максимальное количество повторов для каждого движения равно десяти.
ik.limitByDistance = true; 
ik.distanceLimit = 0.1; 
ik.limitByIteration = true; 
ik.iterationLimit = 10; 

Перемещение каркаса ОК

Объект IKMover передвигает вал внутри прослушивателя событий для колеса. При отправке каждого события enterFrame колеса вычисляется новая целевая позиция каркаса. С помощью метода moveTo() объект IKMover перемещает хвостовое соединение в целевую позицию или до ограничения, заданного свойствами limitByDistance , limitByIteration и limitByTime .
Wheel.addEventListener(Event.ENTER_FRAME, frameFunc); 
 
function frameFunc(event:Event) 
{ 
    if (Wheel != null) 
    { 
        var mat:Matrix = Wheel.transform.matrix; 
        var pt = new Point(90,0); 
        pt = mat.transformPoint(pt); 
         
        ik.moveTo(pt); 
    } 
} 

Использование пружин

В Flash Professional CS5 модуль обратной кинематики поддерживает костную пружину. Костную пружину можно настроить во время разработки, а ее атрибуты можно добавлять или изменять прямо во время выполнения. Пружина Spring — это свойство кости и ее суставов. Она имеет два атрибута: IKJoint.springStrength , который задает усилие пружины, и IKJoint.springDamping , который складывает сопротивление и усилие, что влияет на скорость демпфирования колебаний пружины.

Усилие пружины выражается в процентах от 0 (максимально жесткая) до 100 (максимально мягкая, управляемая физикой). Кости с пружиной реагируют на движения своих суставов. Если не применяется других типов поступательного движения (по оси X или Y, вращение), настройки пружины не действуют.

Демпфирование пружины выражается в процентах от 0 (нет сопротивления) до 100 (максимальное сопротивление). Демпфирование влияет на время, которое проходит после начала движения кости и до ее возвращения в состояние покоя.

Чтобы узнать, включены ли пружины для объекта IKArmature, проверьте свойство IKArmature.springsEnabled . Остальные свойства и методы пружины принадлежат отдельным объектам IKJoint. Сустав может поддерживать угловой поворот и поступательное движение вдоль осей X и Y. Задать расположение угла вращательной пружины поворачиваемого сустава можно с помощью свойства IKJoint.setSpringAngle , а расположение пружины поступательного сустава — с помощью свойства IKJoint.setSpringPt .

В данном примере производится выбор кости по имени и идентификация ее свойства tailJoint. Код проверяет родительский каркас, чтобы узнать, поддерживают ли он пружины, а затем задает свойства пружины для сустава.

var arm:IKArmature = IKManager.getArmatureAt(0); 
var bone:IKBone = arm.getBoneByName("c"); 
var joint:IKJoint = bone.tailJoint; 
if (arm.springsEnabled) { 
    joint.springStrength = 50; //medium spring strength 
    joint.springDamping = 10; //light damping resistance 
    if (joint.hasSpringAngle) { 
        joint.setSpringAngle(30); //set angle for rotational spring 
    } 
}

Использование событий ОК

Класс IKEvent позволяет создать объект события, содержащий сведения о событиях ОК. Информация объекта IKEvent описывает движение, которое прекращено в результате достижения указанного ограничения по времени, расстоянию или числу повторов.

В следующем коде регистрируется прослушиватель и обработчик событий для отслеживания событий ограничения по времени. Этот обработчик событий сообщает сведения о времени, расстоянии, количестве повторов и свойствах соединения для события, которое отправляется при превышении ограничения по времени, установленного для объекта IKMover.

var ikmover:IKMover = new IKMover(endjoint, pos); 
ikMover.limitByTime = true; 
ikMover.timeLimit = 1000; 
 
ikmover.addEventListener(IKEvent.TIME_LIMIT, timeLimitFunction); 
 
function timeLimitFunction(evt:IKEvent):void 
{ 
    trace("timeLimit hit"); 
    trace("time is " + evt.time); 
    trace("distance is " + evt.distance); 
    trace("iterationCount is " + evt.iterationCount); 
    trace("IKJoint is " + evt.joint.name); 
}