Skinning Teil 1

Ein Beispiel-SkelettEin Beispiel-Skelett

Mittels Skinning ist es möglich 3D-Figuren zu animieren. Das Prinzip ist ähnlich wie in der Natur: Haut ("Skin") und Fleisch befinden sich auf einem Knochenskelett. Muskeln greifen an den Knochen an um mit ihnen die Haut zu bewegen. Sie bewegt sich mit, da sie fest mit dem Rest des Körpers verbunden ist. Das Skinning zur Animation von virtuellen Figuren funktioniert ähnlich: Indem Knochen direkt durch Transformationen bewegt werden. Das Mesh selbst stellt das Skin dar. Jedem Knochen ("Bone") des Skeletts werden nun Teile des Skins zugeordnet die sich mit der Bone bewegen sollen. Da es auch möglich ist, dass ein Bereich durch mehrere Bones beeinflusst wird, wird den Zuweisungen noch eine Gewichtung hinzugefügt - dadurch kann festgelegt werden wie stark eine Bone die Position eines Punkts ändert.

Die folgenden zwei Bilder zeigen jeweils zwei Bones mit den ihnen zugeordneten Vertices. Auf dem ersten Bild sieht man, dass der Bone1 die vier ganz linken Punkte zugeordnet sind (der rote Bereich). Auf dem zweiten Bild sind die Punkte der Bone2 hervorgehoben.

2 Bones, die Vertices der ersten Bone markiert2 Bones, die Vertices der ersten Bone markiert
2 Bones, die Vertices der zweiten Bone markiert2 Bones, die Vertices der zweiten Bone markiert

Wird nun die Bone2 bewegt, so bewegen sich die ihr zugeordneten Punkte enstprechend mit:

Eine einfache Pose mit zwei BonesEine einfache Pose mit zwei Bones

Wenn man genau hinsieht, dann stellt man fest, dass die Punkte die der Bone1 zugeordnet wurden sich überhaupt nicht verändert haben. Lediglich die Punkte der Bone2 nehmen an der Bewegung teil.

Wenn einem Punkt immer nur eine Bone zugeordnet wird, kann das aber zu Problemen bei der Animation von bestimmten geometrischen Strukturen führen. Dies ist bei folgendem Beispiel zu sehen:

Y-Aufbau mit den Vertices der Bone 3 markiertY-Aufbau mit den Vertices der Bone 3 markiert
Y-Aufbau mit den Vertices der Bone 2 markiertY-Aufbau mit den Vertices der Bone 2 markiert

Auf diesen Bildern sieht man, dass der Punkt an denen sich die Schenkel des Y treffen beiden Bones zugeordnet ist. Dies ist essentiell, denn wenn Bone2 bewegt wird und der Punkt ist nicht beiden zugeordnet, sieht das so aus:

Y-Aufbau mit ungewichtetem Vertex im ScheitelpunktY-Aufbau mit ungewichtetem Vertex im Scheitelpunkt

Wird der Punkt jedoch mit beiden Bones verbunden, ist das Ergebnis viel harmonischer:

Y-Aufbau mit gewichtetem Vertex im ScheitelpunktY-Aufbau mit gewichtetem Vertex im Scheitelpunkt
Y-Aufbau mit Pose und gewichteten VerticesY-Aufbau mit Pose und gewichteten Vertices

Die Bone-Daten

Jede Bone besitzt einen Ursprung, eine Ausrichtung und eine Länge. Diese Angaben beziehen sich stets auf das Koordinatensystem ihres Vaters - bzw. bei der Root-Bone auf das Ursprungs-Koordinatensystem.

Die Daten einer BoneDie Daten einer Bone

Auf dem oberen Bild sieht man in rot das Koordinatensystem das diese Bone an ihre Kinder weitergibt und welches dann für deren Kinder wiederum als Vater-Koordinatensystem fungieren wird. Das Koordinatensystem der Bone selbst ist in grün eingezeichnet. Es handelt sich aus dem Grund um ein anderes, da die Drehung der Bone natürlich um ihren Ursprung erfolgen sollte und dann sollte ihr Koordinatensystem sich natürlich ebenfalls um seinen Ursprung drehen.

Ursprung Der Ursprung ist der Punkt um den die Bone sich dreht wenn sie bei einer Animation rotiert wird.
Ausrichtung

Die Ausrichtung ist die Richtung in der Ruheposition der Bone - dies ist jene Orientierung, die sie annimmt wenn keine Bewegung ausgeführt wird. In dieser Ruheposition liegt eine Bone in der Regel genau in dem Körperteil im Mesh den sie animiert. Eine Bone für den Oberschenkel befindet sich in Ruheposition also genau dort wo das Meshobjekt so wie es modelliert wurde den Oberschenkel hat.

Die Animation der Bones wird realisiert, indem zusätzlich zu dieser Orientierung noch weitere Matrizen verwendet werden, welche dann die Bone in ihre Pose aus der Animation bewegen.

Länge Über die Länge bestimmt die Bone wo das von ihr für die Kinder erzeugte Koordinatensystem den Ursprung hat.

Die Ausrichtung wird über eine Matrix, der Ursprung über einen Vektor und die Länge über einen float-Wert definiert. Allein durch diese Informationen zusammen mit allen Vater-Kind-Beziehungen ist es möglich ein komplettes Skelett darzustellen:

Ein Beispiel-SkelettEin Beispiel-Skelett

Dieses Beispiel-Skelett befindet sich aktuell in seiner sogenannten "Rest-Position" (Ruheposition). Diese Position bedeutet, dass keine der Bones aktuell eine Animationsmatrix anwendet: Alle Bones befinden sich in ihrer normalen, unveränderten Ausrichtung.

Eine besondere Stellung nimmt die Root-Bone ein: Dies ist die Bone die keinen Vater hat. Von ihr gibt es in jedem Skelett genau eine.

Durchführung des Skinnings

Um nun die Punkte des Mesh zusammen mit ihrem Bones zu bewegen sind folgende Schritte notwendig:

Als Vorraussetung ist festzuhalten, dass die Punkte des Mesh Objekts sich alle im Ursprungssystem befinden - also in dem gleichen System wie die Root-Bone.

  • Step 1) die Punkte $ P_k $ jeder Bone aus dem Ursprungssystem in das lokale Bone-System transformieren: -> $ Q_k $
  • Step 2) die Punkte $ Q_k $ werden nun mit der Matrix der Animationspose transformiert -> $ T_k $
  • Step 3) die Punkte $ T_k $ werden abschliessend wieder zurück in ihr Ursprungssystem transformiert. -> $ Z_k $

Diese Schritte möchte ich nun im einzelnen genauer beschreiben:

Step 1: Ursprungssystem -> lokales Bone-System

Die Punkte des Meshes befinden sich alle im Ursprungs-Koordinatensystem. Die Posen der Animationen sind aber im System der Bone definiert. Bevor die Bewegung der Bone auf die Punkte übertragen werden kann, müssen zuerst die Punkte in das Koordinatensystem der Bone gebracht werden:

Für jede Bone i benötigen wir hierfür ihre inverse Rest-Matrix $ R_i^{-1} $. Die Rest-Matrix $ R_i $ jeder Bone i erhalten wir, indem ausgehend von der Root-Bone, die gesamte Hierarchie bis hinunter zur Zielbone alle relativen Matrizen aufmultipliziert werden.

Die relativen Matrizen $ L_i $ sind die, welche die Verschiebung des Ursprungs, die Orientierung und die Verschiebung an das Ende der Bone in einem einzelnen Schritt für jeweils eine Bone durchführen. Durch die Kombination all dieser Transformationen von der Wurzel an erhalten wir für jede Bone die Matrix die Punkte aus dem Ursprungssystem in ihr lokales Bone-System bringen kann. Durch Invertieren dieser Matrix erhalten wir dann die gesuchte inverse Rest-Matrix für die Bone i: $ R_i^{-1} $

$ L_i =  T_i(Ursprung) \times O_i \times T_i(Länge) $

mit

$ R_i =  R_{parent}(i) \times T_i(Ursprung) \times O_i $

Li Relative Matrix die alle Transformationen einer Bone anwendet
Ri Matrix die Punkte aus dem System der Bone i in das Ursprungssystem transformiert.
Rparent(i) Die Matrix R für den Vater der Bone i
Ti(Länge) Translationsmatrix die das Koordinatensystem um die Länge entlang der Y-Achse verschiebt
Ti(Ursprung) Translationsmatrix die das Koordinatensystem an den Ursprungspunkt der Bone i verschiebt
Oi Translationsmatrix die die Orientierung der Bone i anwendet
Pk Die Originalen Punkte des Mesh Objekts
Ai Die Matrix die die Pose für die Bone i festlegt

wobei gilt:

$ R_{root bone} $ = Identity matrix

Für die zu berechnenden Punkte gilt somit: $ Q_k = R_i^{-1} \times P_k $ für alle Punkte k die der Bone i zugeordnet sind.

Step 2: Animieren der Punkte

Die Animation ist ein einfacher Schritt: Hier werden die Punkte die in Step 1 errechnet wurden mit der Animationsmatrix Ai multipliziert.

Für die zu berechnenden Punkte gilt somit: $ T_k = A_i \times Q_k $

Step 3: Zurück ins Ursprungssystem

Die animierten Punkte aus Step 2 werden in diesem Schritt wieder zurück in ihr Ursprungssystem befördert. Sie dürfen aber nicht einfach wieder in ihr ehemaliges System zurück - die Vater-Bones wurden vermutlich auch animiert und daher muss die Bone nicht in ihr Ruhesystem zurück, sondern in das durch den Vater neu positionierte System. Dies erreicht man, indem während der Pose-Berechnung aller Bones das durch die Pose veränderte Koordinatensystem an die Kinder weitergegeben wird und diese sich dann aus ihrem Ruhesystem in das neue übergebene System bewegen.

Das folgende Bild zeigt wie sich zwei Bones bewegen. Durch die Drehung der grauen Bone in die schwarze Position verändet sich das Koordinatensystem in dem sich die grün dargestellte Kind-Bone bewegt.

Die Koordinatensysteme beim posieren einer BoneDie Koordinatensysteme beim posieren einer Bone

Die Matrix die diese Operation durchführen kann ist $ R'_i $. Dies sei die Matrix die analog zur Matrix R gebildet wird, wobei jedoch nicht nur die Rest-Matrizen für die Bone-Matrizen verwendet werden, sondern dazu auch die Pose-Matrizen:

$ R'_i =  R'_{parent}(i) \times T_i(Ursprung) \times O_i \times Pose_i $

wobei wieder gilt: $ R'_{root bone} $ = Identity Matrix

Für die zu berechnenden Punkte gilt somit: $ Z_k = R'_i \times T_k $

Nach dem Abschluss dieser Berechnungen sind $ Z_k $ die Punkte des Meshes auf die das Skinning angewandt wurde und die nun gezeichnet werden können!

Zusammenfassung

Ein Punkt $ P_k $ der von der Bone i beeinflusst wird erhält seine neue Position $ Z_k $ durch die Formel:

$ Z_k = R'_i \times A_i \times R_i^{-1} \times P_k $

Gewichtungen berücksichtigen

Etwas, das bisher noch fehlt ist die Berücksichtigung der Gewichtung. Ein Faktor (0 bis 1) wird mit jeder Animationsmatrix $ A_i $ multipliziert bevor diese zur Transformation eines Punkts benutzt wird. Wenn ich die Implementierung des Skinnings über den Vertex-Shader beschreibe gehe ich auf diesen Schritt aber noch genau ein.

Dieser Artikel beschäftigte sich erst mal mit den Grundlagen des Skinnings und mit den mathematischen Berechnungen die dafür notwendig sind. Der folgende zweite Teil wird die konkrete Implementierung des Skinnings vorstellen.

OpenGLBlenderDrupal poweredSpieleentwicklertreff NRW