Praca z kinematyką odwrotną

Flash Player 10 i nowsze wersje, Adobe AIR 1.5 i nowsze wersje, wymagany program Flash CS4 lub nowszy

Kinematyka odwrotna (IK) to wspaniała technika tworzenia realistycznych ruchów.

IK umożliwia tworzenie skoordynowanych ruchów w łańcuchu połączonych części nazywanych szkieletem IK, dzięki czemu części poruszają się jak w rzeczywistości. Części szkieletu są jego kości i stawami. Na podstawie punktu końcowego szkieletu IK oblicza kąty dla stawów, które są wymagane do uzyskania konkretnego punktu końcowego.

Samodzielne obliczanie tych kątów byłoby bardzo trudne. Zaletą tej funkcji jest to, że można tworzyć szkielety interaktywnie za pomocą programu Adobe® Flash® Professional. Następnie można animować szkielety za pomocą języka ActionScript. Silnik IK zawarty w programie Flash Professional wykonuje te obliczenia w celu opisania ruchu szkieletu. Ruch można ograniczyć do pewnych parametrów w kodzie ActionScript.

Nowością wprowadzoną do mechanizmu kinematyki odwrotnej w wersji Flash Professional CS5 jest koncepcja sprężynowania kości, kojarzona zazwyczaj z aplikacjami do tworzenia zaawansowanych animacji. Dzięki nowemu mechanizmowi symulacji fizycznej dynamiki ruchu funkcja ta umożliwia tworzenie realistycznych animacji. Efekt ten jest widoczny zarówno w środowisku wykonawczym, jak i podczas tworzenia treści.

Do tworzenia szkieletów kinematyki odwrotnej wymagana jest licencja programu Flash Professional.

Podstawowe informacje o kinematyce odwrotnej

Kinematyka odwrotna (IK) umożliwia tworzenie realistycznych animacji poprzez łączenie części w taki sposób, aby poruszały się względem siebie w sposób realistyczny.

Na przykład: za pomocą IK można przesunąć nogę do określonego miejsca poprzez wykonywanie ruchów zginania w stawach nogi, która ma osiągnąć wymagane położenie. IK korzysta ze struktury kości połączonych ze sobą w strukturę o nazwie szkielet IK. Pakiet fl.ik ułatwia tworzenie animacji przypominających ruch naturalny. Umożliwia płynne animowanie wielu szkieletów IK bez konieczności posiadania szczegółowej wiedzy na temat zasad fizyki w algorytmach IK.

Najpierw należy utworzyć szkielet IK z pomocniczymi kośćmi i stawami w programie Flash Professional. Następnie należy uzyskać dostęp do klas kinematyki odwrotnej w celu animowania szkieletu w środowisku wykonawczym.

Szczegółowe informacje dotyczące tworzenia szkieletów kinematyki odwrotnej zawiera sekcja poświęcona korzystaniu z kinematyki odwrotnej w dokumentacji Korzystanie z programu Flash Professional .

Ważne pojęcia i terminy

Na poniższej liście objaśniono ważne terminy istotne w kontekście tego zagadnienia:

Szkielet
Łańcuch kinematyczny zawierający kości i stawy, używany w animacji komputerowej do symulowania realistycznych ruchów.

Kość
Sztywny segment szkieletu, analogiczny do kości w szkieletach zwierząt.

Kinematyka odwrotna (IK)
Proces określania parametrów połączonego stawami elastycznego obiektu, który jest nazywany łańcuchem kinematycznym lub szkieletem.

Staw
Miejsce, w którym łączą się dwie kości. Umożliwia ruch kości; analogiczny do stawów u zwierząt.

Silnik Physics
Pakiet algorytmów fizycznych wykorzystywanych w celu tworzenia realistycznych ruchów w animacjach.

Sprężyna
Cecha kości, która porusza się i reaguje w przypadku przesunięcia kości nadrzędnej, a następnie intensywność reakcji zmniejsza się w miarę upływu czasu.

Przegląd animacji szkieletów kinematyki odwrotnej

Po utworzeniu szkieletu IK w programie Flash Professional należy użyć klas fl.ik w celu ograniczenia jego ruchu, śledzenia zdarzeń i animowania szkieletu w środowisku wykonawczym.

Poniższa ilustracja prezentuje klip filmowy o nazwie Wheel. Oś jest instancją IKArmature o nazwie Axle . Klasa IKMover porusza szkieletem w synchronizacji z obrotami koła. Kość IKBone, ikBone2 , w szkielecie jest dołączona do koła przy stawie ogonowym.

A.
Koło

B.

C.
ikBone2

W trakcie wykonywania koło obraca się zgodnie z animacją ruchu __motion_Wheel omówioną w sekcji Opisywanie animacji . Obiekt IKMover inicjuje i kontroluje ruch osi. Poniższa ilustracja prezentuje dwa zrzuty szkieletu osi dołączonego do obracającego się koła w różnych klatkach obrotu.

Poruszanie szkieletem IK w dwóch różnych pozycjach
W czasie wykonywania następujący kod ActionScript:
  • Uzyskuje informacje o szkielecie i jego składnikach

  • Tworzy instancję obiektu IKMover

  • Porusza osią w połączeniu z obrotami koła

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); 
    } 
}

Klasy IK używane do poruszania osią:

  • IKArmature: opisuje szkielet — strukturę drzewa, która zawiera kości i stawy; należy utworzyć w programie Flash Professional

  • IKManager: zawiera klasę dla wszystkich szkieletów IK w dokumencie; należy utworzyć w programie Flash Professional

  • IKBone: segment szkieletu IK

  • IKJoint: połączenie między dwiema kośćmi IK

  • IKMover: inicjuje i kontroluje ruchy IK szkieletów

Pełny i szczegółowy opis tych klas zawiera dokumentacja pakiet ik .

Pobieranie informacji o szkielecie kinematyki odwrotnej

Najpierw należy zadeklarować szkielet, kość i staw, które tworzą części, jakie będą się poruszały.

W poniższym kodzie wykorzystano metodę getArmatureByName() klasy IKManager w celu przypisania wartości szkieletu Axle do zmiennej tree klasy IKArmature. Szkielet Axle został poprzednio utworzony w programie Flash Professional.

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

I podobnie — w poniższym kodzie wykorzystano metodę getBoneByName() klasy IKArmature w celu przypisania do zmiennej IKBone wartości kości ikBone2 .

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

Staw ogonowy kości ikBone2 jest częścią szkieletu, która jest dołączona do obracającego się koła.

Poniższa linia deklaruje zmienną endEffector i przypisuje ją do właściwości tailjoint kości ikBone2 :

var endEffector:IKJoint = home.tailjoint;
Zmienna pos jest punktem, który przechowuje bieżącą pozycję stawu endEffector .
var pos:Point = endEffector.position;

W tym przykładzie pos jest pozycją stawu na końcu osi, w miejscu, w którym łączy się z kołem. Oryginalna wartość tej zmiennej jest uzyskiwana z właściwości position stawu IKJoint.

Tworzenie instancji klasy IK Mover i ograniczanie jej ruchu

Instancja klasy IKMover porusza osią.

W poniższej linii tworzona jest instancja obiektu IKMover ik , a do jego konstruktora przekazywany jest element przeznaczony do poruszenia oraz punkt początkowy ruchu:
var ik:IKMover = new IKMover(endEffector, pos);

Właściwości klasy IKMover umożliwiają ograniczanie ruchu szkieletu. Ruch można ograniczyć na podstawie odległości, iteracji oraz czasu ruchu.

Poniższe pary właściwości wymuszają te ograniczenia. Pary zawierają wartość Boolean, która wskazuje, czy ruch jest ograniczony, oraz liczbę całkowitą, która określa limit:

Właściwość typu Boolean

Właściwość typu Integer

Ustawiony limit

limitByDistance:Boolean

distanceLimit:int

Ustawia maksymalną odległość w pikselach, o jaką silnik IK zmieni ustawienie przy każdej iteracji.

limitByIteration:Boolean

iterationLimit:int

Ustawia maksymalną liczbę iteracji wykonywanych w każdym ruchu przez silnik IK.

limitByTime:Boolean

timeLimit:int

Ustawia maksymalny czas w sekundach przydzielony do silnika IK w celu wykonania określonego ruchu.

Domyślnie wszystkie wartości typu Boolean są ustawiane na false , a zatem ruch nie jest ograniczony, o ile wartość Boolean nie zostanie jawnie ustawiona na true . Aby wymusić limit, należy ustawić odpowiednią właściwość na true , a następnie określić wartość odpowiadającej jej właściwości typu Integer. Jeśli zostanie ustawiona wartość limitu, ale nie zostanie określona odpowiednia wartość Boolean, wówczas limit zostanie zignorowany. W takim przypadku silnik IK będzie kontynuował ruch obiektu do czasu osiągnięcia innego limitu lub pozycji docelowej klasy IKMover.

W poniższym przykładzie maksymalna odległość ruchu szkieletu jest ustawiona na 0,1 piksela na iterację. Maksymalna liczba iteracji dla każdego ruchu jest ustawiona na dziesięć.
ik.limitByDistance = true; 
ik.distanceLimit = 0.1; 
ik.limitByIteration = true; 
ik.iterationLimit = 10; 

Poruszanie szkieletem IK

Klasa IKMover porusza osią w detektorze zdarzeń koła. Przy każdym zdarzeniu enterFrame koła obliczana jest nowa pozycja docelowa dla szkieletu. Za pomocą metody moveTo() klasa IKMover porusza staw ogonowy do jego położenia docelowego lub na odległość zgodną z ograniczeniami określonymi przez właściwości limitByDistance , limitByIteration i 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); 
    } 
} 

Korzystanie ze sprężynowania

Mechanizm kinematyki odwrotnej dostępny w aplikacji Flash Professional CS5 pozwala na obsługę sprężynowania kości. Sprężynowanie kości może być ustawiane podczas tworzenia, a atrybuty sprężynowania mogą być dodawane i modyfikowane w środowisku wykonawczym. Sprężystość jest właściwością kości i jej stawów. Właściwość jest opisana dwoma atrybutami: IKJoint.springStrength , który określa stopień sprężynowania, oraz IKJoint.springDamping , który zwiększa tłumienie drgań sprężyny i wpływa na szybkość zaniku efektu sprężynowania.

Stopień sprężynowania to wartość wyrażona w procentach od 0 (domyślnie, całkowita sztywność) do 100 (elastyczność, sterowanie silnikiem Physics). Kości posiadające właściwość Spring reagują na ruch w ich stawach. Jeśli nie wystąpiła żadna zmiana (rotacja, przesunięcie x lub y), wówczas ustawienia sprężynowania nie mają wpływu na zachowanie kości.

Tłumienie sprężynowania to wartość wyrażona w procentach od 0 (brak oporu) do 100 (pełne tłumienie). Tłumienie wpływa na czas, jaki upływa między początkiem ruchu kości a jej powrotem do pozycji spoczynkowej.

Aby sprawdzić, czy sprężynowanie zostało aktywowane dla obiektu IKArmature, należy odczytać jego właściwość IKArmature.springsEnabled . Inne właściwości i metody Spring nalezą do poszczególnych obiektów IKJoint. Staw może umożliwiać obroty i przesunięcia wzdłuż osi x i y. Kąt sprężynowania dla stawu obrotowego można ustawić za pomocą właściwości IKJoint.setSpringAngle , a pozycję sprężyny dla stawu umożliwiającego przesuwanie można ustawić za pomocą właściwości IKJoint.setSpringPt .

Ten przykład ilustruje wybór kości wg nazwy i identyfikację jej właściwości tailJoint. Kod testuje nadrzędny szkielet w celu sprawdzenia, czy sprężynowanie zostało aktywowane, a następnie ustawia właściwości sprężynowania dla stawu.

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 
    } 
}

Korzystanie ze zdarzeń kinematyki odwrotnej

Klasa IKEvent umożliwia utworzenie obiektu zdarzenia, który zawiera informacje dotyczące zdarzeń IK. Informacje w klasie IKEvent opisują ruch, który zakończył się z powodu przekroczenia limitu czasu, odległości lub iteracji.

Poniższy kod prezentuje detektor zdarzenia i moduł obsługi zdarzenia dla śledzenia zdarzeń przekroczenia limitu czasu. Ten moduł obsługi zdarzeń zgłasza właściwości dotyczące czasu, odległości, liczby iteracji i stawu biorącego udział w zdarzeniu w przypadku przekroczenia limitu czasu klasy 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); 
}