Grundlagen der Joint Animation

Synopsis:
es wird gezeigt, wie mittels Carad eine einfache, interaktive, gelenksbasierende Skin Animation erstellt wrd

BaseGraph unterstützt drei verschiedene Animationsformate, welche auch in Carad geladen oder importiert werden können

  • Gelenksanimationen, einem Objekt werden "Gelenke" Zugeordnet, in denen Position und Orientierung gespeichert und animiert werden. Diesen Gelenken können Kindobjekte zugeordnet werden, die über diese dann animiert werden. Jeder Abkömmling von Obj (also jedes 3D-Objekt) hat diese Fähigkeit
  • Frame Animationen, wie bei Videos werden nacheinander in bestimmten, flexiblen Zeitabständen 3D-Meshes zur Videokarte gesandt, die eine Bewegung darstellen. Flüssige Übergänge werden durch Interpolation zwischen den einzelnen Frames erreicht. Nur Abkömmlinge von AniMesh haben diese Fähigkeit. Normalerweise (aber nicht notwendigerweise) werden Gelenksanimationen auf Frame Animationen abgestimmt, wie es etwa bei Quake3 Modellen der Fall ist.
  • Skin Animationen, dies sind die logische Fortführung der Gelenksanimationen, als nicht nur Kindobjekte den Gelenken zugeordnet werden können, sondern auch die einzelnen Schnittpunkte der Objekte. Nur Abkömmlinge von SkinMesh haben diese Fähigkeit.

Um nun in Carad von Grund auf eine Skin Animation zu erstellen, benötigen wir erst mal ein statisches Objekt, das animiert werden soll. In unserem Fall soll dies ein Rohr sein, das wir direkt als Primitive generieren können:

Nicht vergessen, das Rohr oben und unten zu schließen, damit das fertige Objekt "massiv" aussieht. Folgendes Ergebnis sollten wir bekommen:

Nun wandeln wir das statische Objekt in ein SkinMesh um. Dazu stellen wir sicher, dass das Objekt angewählt ist, klicken mit der rechten Maustaste ins 3D-Fenster und wählen den Punkt "in Skinmesh". Das Ergebnis sieht dann folgendermaßen aus:

Gut zu erkennen ist, dass nun sämtliche Schnittpunkte des Objektes angezeigt werden, was ja auch notwendig ist, um sie im Folgenden den einzelnen Gelenken zuordnen zu können. Nun müssen wir aber erst mal die Gelenke definieren, das geschieht im Animationseditor, der mir einem Klick auf diesen Button geöffnet werden kann:

worauf im Feld Joint und ParentJoint folgendeWerte eingegeben werden:

die Bedeutung ist Folgende: wir definieren 6 Gelenke (der Einfachheit halber 1,2,3,4,5,6 genannt), die aneinander hängen sollen. Dies soll folgendermaßen aussehen, dass Gelenk 6 an Gelenk 5 hängt, 5 an 4 und so weiter. Das erste Gelenk hängt automatisch am Ursprung des Objektes und hat deshalb keinen ParentJoint. An die Gelenke gebundene Objekte brauchen wir in diesem Fall ebenfalls nicht, könnten aber später als "Übung" an den Endjoint 6 eine Kugel hängen.

Nachdem die Gelenke definiert wurden, müssen deren lokaler Ursprung gesetzt werden und die Schnittpunkte sollten wir auch zuordnen. Dies sieht folgendermaßen aus, dass wir zuerst das Gelenk wählen (wir fangen mit 1 an), dann die zugehörigen Schnittpunkte per Sweep Selection (Steuerung drücken und Maus bewegen), haben wir die zugehörigen Punkte gewählt, drücken wir "Enter" um die Punkte dem Gelenk zuzuordnen.

Wir stellen sicher, dass das erste Gelenk gewählt ist...

bewegen die Sweep Selection über die entsprechenden Schnittpunkte - Carad erkennt automatisch, dass Schnittpunkte anstelle von Objekten gewählt werden sollen (da eine Skin Animation gewählt ist) und...

die selektierten Schnittpunkte erkennen wir an der anderen Farbe, die sich nach einem Druck auf "Enter"...

intensiviert, wodurch wir erkennen, dass diese dem aktuell gewählten Joint zugeordnet sind.

Nun müssen wir im Animationsfenster im Feld "Base Position" noch den Rotationsmittelpunkt des Joints angeben (mittels Rechtsklick auf das entsprechende Textfeld kann dies über das Kontextmenü auch interaktiv geschehen) - oder aber diesen mittels Druck auf die "C"-Taste (für center) auf den Mittelpunkt der dem Joint zugeordneten Schnittpunkte setzen, was in diesem Fall ausreicht.

Diese Prozedur wiederholen wir für die Gelenke 2 bis 6, wodurch wir am Ende mit folgendem Bild belohnt werden:

Die Verbindungsstücke zwischen zwei Gelenken werden graphisch dargestellt, wobei ein "Knochen" immer von "schwarz" nach "weiß" geht.

Die Gelenke sind nun definiert, für inverse Kinematik würde dies (nach Definition der Fixpunkte für die Endgelenke) bereits ausreichen. Wir wollen aber eine fest vorgegeben Animation haben, bzw. deren zwei, zwischen denen mittels Tastendruck umgeschaltet werden kann.

Dies geschieht nun folgendermaßen (den nächsten Abschnitt bitte genau und eventuell mehrmals durchlesen)

1) wir definieren eine Animation, denen die nachfolgenen Aktionen zugeordnet werden. Die Animation heißt einfach Turn1, Namen eingeben, Enter drücken, und schon steht sie da und harret der Dinge die da kommen

2) wir selektieren den Joint, der animiert werden soll, in diesem Fall ist dies Gelenk 2

3) wir geben die Rotations- und Translationkeys ein. Für dieses Beispiel werden nur RotationKeys benötigt. die beiden Keys sind schnell eingegeben (von 0 Grad um die Y-Achse auf 30 Grad um die Y-Achse rotiert werden) und werden automatisch Gelenk 2 zugeordnet, da dieses selektiert ist.

4) wir wählen die Animation aus, die einen Zyklus erhalten soll (ein Zyklus ist die Animation eines Gelenks über eine bestimmte Zeitspanne). Da es zur Zeit ohnehin nur eine gibt (Turn1), sollte diese bereits gewählt sein.

5) wir definieren das Gelenk, das animiert werden soll (2) und sagen, ober der Zyklus loopen soll (sich ewig wiederholen) oder nicht. FALSE als zweiter Parameter definiert eine einmalige Aktion.

6) wir wählen den Zyklus, dem neue Frames zugeordnet werden sollen. Turn1 hat nur einen Zyklus über das Gelenk 2, daher sollte dies bereits der Fall sein.

7) wir sagen im Feld "Frame Rotation" zu welcher Zeit das der gewählte Zyklus welchen Rotationsframe annehmen soll. Zum Zeitpunkt 0 Millisekunden soll der Frame 0 dargestellt werden, bei 3000 Millisekunden soll es Frame1 sein

8) die Schritte 2 bis 7 wiederholen wir für die Gelenke 3 bis 6, die wir der Einfachheit alle gleich animieren

Nachdem wir nun wissen, wie eine Animation erstellt wird, brauchen wir für das kleine Demo noch zwei weitere Animationen:

Turn2 schaut genau gleich aus wie Turn1, nur dass die Gelenke 2-7 in drei Sekunden von 0;0;0 nach 0;-30;0 rotiert werden (d.h. wir müssen zu den RotationKeys noch jeweils den Key 0;-30;0 hinzufügen und das Feld Frame Rotation schaut dann für die entsprechend Zykel so aus:

0; 0
2; 3000

Default ist eine weitere Animation, die allerdings nur den Ausgangszustand darstellt. Sämgliche Zykel in Default erhalten genau einen RotationsFrame der folgendermaßen definiert ist:

0; 0

Mit <STRG><A> (oder einem Klick auf ) können wir uns immer ansehen, wie die aktuell gewählte Animation gerade aussieht.

Am Ende sollte der Animationseditor ungefähr so aussehen:

Für das Wechseln der laufenden Animation bei der Darstellung, kann übrigens auch das Objektfenster genutzt werden - einfach die entsprechende Animation auswählen:

Soweit, so gut - theoretisch könnten wir das Ganze nun speichern und mit den Animationen herumspielen. Nachdem das Ganze aber ohnehin schon etwas länglich geworden ist, peppe ich das Ganze optisch noch ein wenig auf, sodass die Szene dann so aussieht:

Für das Tutorial ist dies aber unwichtig - wichtig für das weitere Vorgehen, ist es hingegen, die Szene jetzt als Delphi Source mit VCL Unterstützung zu speichern, da ich des Weiteren der Einfachheit halber auf die Steuerelement derselben zurückgreifen werde.

Im Hauptformular werden dann vier Buttons hinzugefügt (Turn1, Turn2, Default, Quit - oder auch nur Button1, Button2, Button3, Button4 :^) ), das Create Ereignis ändern wir folgendermaßen, nachdem wir eine globale Variable ActAnimation hinzugefügt haben:

// initialize environment and objects
InitSkinAnim;
ShowObj(Map);
ShowObj(Skin);
ShowObj(Sphere);
ActAnimation := 2;
Skin.ShowAnimation(ActAnimation);

dann ergänzen wir noch die entsprechenden Ereignisbehandlungsroutinen der Buttons, um zwischen den Animationen wechseln zu können:

procedure TFormSkinAnim.Button1Click(Sender: TObject);
begin
if ActAnimation=0 then exit; // aktuelle Animation muss nicht ersetzt werden
Skin.ResetAnimation(0);
if ActAnimation=2 then
Skin.ReplaceAnimation(ActAnimation, 0, 0) // bei Standbild kann sofort gestartet werden
else
Skin.ReplaceAnimation(ActAnimation, 0, 1000); // 1000 Millisekunden bis zum Start der neuen Animation interpolieren
ActAnimation := 0;
end;
procedure TFormSkinAnim.Button2Click(Sender: TObject);
begin
if ActAnimation=1 then exit; // aktuelle Animation muss nicht ersetzt werden
Skin.ResetAnimation(1);
if ActAnimation=2 then
Skin.ReplaceAnimation(ActAnimation, 1, 0) // bei Standbild kann sofort gestartet werden
else
Skin.ReplaceAnimation(ActAnimation, 1, 1000); // 1000 Millisekunden bis zum Start der neuen Animation interpolieren
ActAnimation := 1;
end;
procedure TFormSkinAnim.Button3Click(Sender: TObject);
begin
if ActAnimation = 2 then exit; // aktuelle Animation muss nicht ersetzt werden
Skin.ReplaceAnimation(ActAnimation, 2, 1000); // 1000 Millisekunden bis zum Standbild interpolieren
ActAnimation := 2;
end;
procedure TFormSkinAnim.Button4Click(Sender: TObject);
begin
Halt(0);
end;

Und haben es geschafft, eine interaktive Animation zu erstellen. Für ein ein komplexeres Projekt, sollte de Wechsel zwischen den Animationen natürlich automatisiert werden, man sieht aber, dass der Aufwand mit Hilfe von BaseGraph gar nicht so aufwändig ist.

Ich hoffe, das Prinzip von Skin Animationen (eventuell auch für eigene Implementierungen), bzw. deren Umsetzung in BaseGraph, ist klar geworden, das fertige Delphiprojekt steht auch in der Projekte & Demos Sektion zur Verfügung - bzw. kann hier direkt heruntergeladen werden.
Viel Spass beim Programmieren,