Ergebnis 1 bis 16 von 16

Thema: 2D Bone Animation?

  1. #1

    2D Bone Animation?

    Moin, moin!

    Ich möchte ein 2D Animationssystem auf der Basis von Bones machen mithilfe von Meshes, Keyframes und Interpollieren.

    Ich hatte mir daher das hier gut durchgelesen: hier
    Allerdings muss das ganze gut flexibel sein, damit ich dass zum Beispiel mit Rigid-Body-Physics kombinieren kann. Was mein Problem dabei ist, ich weiß nicht ganz, auf welche Techniken ich jetzt setzen soll.

    Folgende Sachen muss ich entscheiden, und ich hoffe, dass ihr mich da etwas beraten könnt.

    Welches Bone-System:
    -Position ( evtl. relativ zum vorherigen "parent-bone" ) mit Winkel und Länge
    -Zwei Punkte pro Bone ( praktisch, wenn die Figur zerfetzen soll )
    -Nur Verbindungspunkte zwischen Bones ( Drei statt vier Punkte um 2 Bones darzustellen )

    Welche Daten-Struktur:
    -Die sogenannte Hierarchie Struktur. Es gibt einen "Master Bone" der sich in einzelne oder mehrere "Children Bones" auteilen kann, mithilfe von Linked List oder Arrays für jeden Bone.

    -Andere (?)

    Welche Dimension:
    schlicht 2D, od aber 3D, um komplexere und realistischere Animationen zu erstellen.
    An der Stelle sei gesagt, ich will hauptsächlich damit Sprites animieren. Sprich, ich hab eine Figur als Textur und teile diese in Arme, Beine etc. auf und lege sie auf die Bones mithilfe der Meshes.
    Oder aber ich benutze zwar 3D für die Bones, aber die Meshes bleiben 2D, also nur Polygone. Allerdings weiß ich dann nicht, wie gut das mit der ausschließlich auf 2D beschrännkten Physik-Engine zusammenpasst.

    Hier kann man sehr gut sehen, wie ich das meine: http://www.youtube.com/watch?v=pt8np_qKMlY

    Sonstiges (?)

    Hm, mehr fällt mir grad nicht ein, was so anstünde. Ich hoffe aber, es ist etwas klar, wo meine Problematik liegt. ich will nicht einfach anfangen, um dann nachher feststellen zu müssen, dass es anders vielleicht besser ginge...

    Bye! o/

  2. #2
    Also ich kenn mich jetzt nur mit Joints und Bones in 3D Software aus, aber das ließe sich sicher auch auf eine 2D Software übertragen.
    Cinema 4D benutzt ein gutes System das wie folgt arbeitet:

    Du hast dein Mesh, und du hast Joints - also Gelenke. Diese Joints werden in einer Hierachie angeordnet, z.B. Hüftgelenk -> Knie -> Fußgelenk. Man platziert also die Gelenke, die Fix im Abstand zu den vorherigen Gelenken stehen, und sich rotieren lassen. Die Bewegung des Hüftgelenks bewegt also auch das Kniegelenk und das Fußgelenk mit. Einzelne Drehung der unteren Gelenke ist aber natürlich auch möglich.

    Die einzelnen Joints werden nun optisch per Bones verbunden, auch wenn diese praktisch keinen Nutzen haben, außer dass man die Verbindungskette sieht. Denn die Zuordnung des Mesh geschieht zu den Joints. Die Vertices des Oberschenkels werden also dem Hüftgelenk zugeordnet, das Schienbein dem Kniegelenk etc. Eine Drehung des Knies bewirkt damit das Anwinkeln des Schienbeins, so wie es sich gehört. Und mit dem rechten Hüftgelenk dreht man das ganze rechte Bein. Es entspricht damit also einem echten Gelenk.
    Zuordnen tut man die Vertices in Cinema indem man die Intensität "aufmalt". Jedes Joint kann beliebig viele Punkte des Mesh beliebig stark betreffen. Die Intensität von 0 - 100 % malt man mit einem Pinsel auf. Dort wählt man die Größe und wie deckend und wie "Soft" der Pinsel sein soll, ähnlich also wie in Photoshop.
    Das ganze lässt sich natürlich auf 2D übertragen. Dort hast du dann eben dein Mesh und die Vertices und die Joints-Hierachie. Dann wählst du dort das entsprechende Joint aus, wählst das Wichten-Werkzeug und zeichnest die Intensität auf das Mesh. In 2D dürfte das sogar sehr gut gehen, bei 3D muss man hingegen viel drehen und testen und die Perspektive ändern.
    Grafisch kannst du die Wichtung beim Erstellen der Charaktere übrigens sehr hübsch darstellen, indem du stark gewichtete Punkte sehr hell darstellst und nicht gewichtete Punkte schwarz. Der Verlauf der punkte zeigt dir, wie stark gewichtet wurde.

    Was du also für dein System brauchst ist die Möglichkeit, Gelenke zu zeichnen und eine Möglichkeit, die Wichtung zu zeichen und das Mesh damit an die Joints zu binden. Das Animieren geschieht dann über das Drehen der Joints.

    Im letzten Schritt kannst du dich natürlich auch mit IK (Inverse Kinematik) auseinander setzen. Also statt die Joints manuell zu rotieren (FK - Forward Kinematik) kannst du ein Ziel für den Fuß festlegen und der Fuß versucht immer dieses Ziel zu erreichen. Die Beine bzw die die Gelenke verdrehen sich entsprechend, sodass es passt. Das dürfte mathematisch nicht ganz unproblematisch zu realisieren sein (steckt viel Geometrie und Winkelberechnungen drinn), aber erzeugt sehr realistische Bewegungen und vereinfacht das spätere Animieren sehr.


    Achso, und wie du die die Daten später speicherst kannst du dir ja frei wählen. Bei 2D fällt immerhin eine Koordinate und 2 Winkel weg. Jeder Joint braucht eine Position und einen Winkel und die Information, welche Punkte er wie stark beeinflusst. Die Wichtung kannst du in einer Linked List speichern, dort bekommt jeder Punkt des Mesh eine Nummerierung und dann speicherst du dir die Nummer und die Wichtung von 0 - 100 (%). So kannst du flexibel gewichtete Punkte in der Liste dynamisch hinzufügen.
    Die Joints kannst du natürlich auch in einer Linked-List speichern. Dort musst du berücksichtigen, dass jedes Joint mehr als ein Child-Joint haben kann - aber nur ein Parent. Du brauchst also für die Child-Verlinkung ebenfalls wieder eine Linked-List. Damit hat jedes Listenelement eine Liste inbegriffen, welche die Childs beinhaltet. Dadurch kannst du dann eine Hierachie für die Joints erzeugen. Es geht also darum, dynamisch Linked-Lists anzulegen und in einer Hierachie zu verwalten. Wie du die Daten dann letztendlich speicherst bleibt natürlich dir überlassen.

    Die Länge des "Bones" - also der Abstand der beiden Joints, kannst du - musst du aber nicht - mit speichern. Denn diese ergibt sich ja auch schon durch die beiden Positionen der Joints, wenn du diese miteinander vergleichst. Da brauchst du dann ein bissel Vektorrechnung, aber im 2D-Raum ist es noch einfacher als 3D.

    Geändert von Ynnus (05.03.2010 um 22:46 Uhr)

  3. #3
    Danke für deine Antwort!

    Aber naja, ehrlich gesagt waren das die Sachen, die ich schon wusste, weil genau eben das in dem Tutorial erklärt wird.
    Aber das mit dem Pinsel Werkzeug klingt eigentlich ganz gut. Ich muss mir glaub ich zwar ein paar Videos anschauen, wie das denn in Cinema4D aussieht ( kanns mir nicht ganz vorstellen ), aber wenn du das so begeistert darstellst

    Und joa, ich werde denk ich Inversed Kinematik benutzen, ist wirklich einfacher.

    Trotzdem danke! o/

  4. #4
    Naja, technisch könnte man das mit dem Pinsel z.B. so realisieren:

    Du hast dein Mesh und ein Joint ausgewählt, für den die Punkte gewichtet werden sollen. Jetzt wählst du für den Pinsel einen Radius und wie weich die Pinselspitze sein soll und zeichnest über das Mesh. Da man ja kreisförmig, mit definiertem Radius zeichnet, kannst du z.B. die gezeichnete Wichtung abhängig machen zum Abstand zum Mittelpunkt des Pinsels. Punkte, die weiter vom Mittelpunkt entfernt werden, werden damit "softer" gewichtet, in 1 - 2 % Schritten, wohingegen Punkte direkt unter dem Pinsel-Ursprung z.B. mit 10 % gewichtet werden. Wenn du öfter drüber fährst addieren sich die Wichtungen, bis zu 100 % eben. Wie stark per "Pinselstrich" gewichtet wird kannst du den Benutzer ja in der GUI einstellen lassen. Ebenfalls dann auch die Abnahme der Pinselspitze, also Linear, Glockenförmig, Nadelförmig, oder ohne Abnahme etc.

    Als Alternative zum Zeichnen der Punkte steht natürlich das Manuelle Auswählen der Punkte und dem Zuweisen eines gewichteten Wertes. Aber das ist viel Arbeit und man muss Übergänge und Abnahmen manuell durch kleinere und größere Werte eingeben. Per "Aufmalen" kann das automatisch geschehen.

    EDIT: Mit der Beschreibung, wie es Cinema realisiert, wollte ich dir auch nur einen Weg vorschlagen, wie es sicherlich nicht verkehrt ist. Cinema ist seit einiger Zeit von Bones auf Joints umgestiegen und das stellt normalerweise die modernere Methode dar. Wenn du dich also nicht entscheiden kannst würde ich Joints mit Position und Winkel und einer Hierachie empfehlen.

    EDIT2: Hier kannst du dir angucken wie das Arbeiten mit dem Weight-Tool aussieht: http://www.youtube.com/watch?v=KNra8aD3QKU

    Geändert von Ynnus (05.03.2010 um 23:29 Uhr)

  5. #5
    Achso, das hab ich irgendwie nicht ganz rausgelesen, dass du meintest, ich solle wirklich auf die Joint ohne wirkliche Bones setzen ( Die Joints bilden indirekt ja die Bones ).

    Hm, jetzt hab ich mal so angefangen, und bin auf ein ziemliches Problem gestoßen.
    Nämlich gibt es bei Freebasic, dass ich benutze keine Linked-List. Das ist erstmal nicht weiter schlimm, da ich mir dafür was geschrieben hab.
    Das Funktioniert so, dass ein Makro aufrufe, dem ich den Datentyp der Liste und den Namen übergebe und in dem Makro eine Struktur mit eben jenem Datentyp als Speicherinhalt erstellt.

    Jetzt ist in der Struktur der Bones ja eine Liste mit den Children Bones. Sprich, in der bone Struktur ist wieder ein Bone drin.

    Allerdings kann ich das Makro erst benutzen, wenn die Struktur schon erstellt ist, also kann ich in die Struktur die Liste nicht einfügen.

    Leider gibt es auch noch keine dynamischen Arrays innerhalb von Strukturen. Ich könnte natürlich ein Array mit fester Größe und Counter benutzen, aber ich find das immer nicht so schön und nicht sehr flexibel...

    Jetzt weiß ich nicht ganz weiter, ob ich vielleicht eine einfache Integerliste habe, die nur die IDs oder so speichert, oder aber ich arbeite Any Pointern, Also Pointer, die auf jeden Datentyp zeigen können. Allerdings hab ich da immer meine Probleme mit...

    Hilfe! ;_;

    Geändert von Teflo (06.03.2010 um 11:48 Uhr)

  6. #6
    Ist FreeBasic objektorientiert? Das würde vieles einfacher machen und du könntest dir ganz einfach selbst eine Linked-List bauen indem du eine Klasse für die Listen-Elemente erzeugst und da dynamisch neue Objekte generierst und mit den vorherigen Elementen verkettest.

    Ansonsten - über den Tellerrand blicken und auf C/ C++ umsteigen.

  7. #7
    Ja, ich glaub schon, dass das Objektorientiert ist. Zumindest habe ich da "User defined Types" in welchen mehrere Variablen und funktionen etc. zusammengefasst sind.
    Und so eine Linked List hatte ich mir zwar schon geschrieben, aber um eine Linked List zu erstellen, muss das jeweilige Objekt ersteinmal existieren, daher funktioniert das nicht schon beim erstellen des Objektes.

    Naja, ich hatte mir an der Stelle auch gedacht, ob ich nicht endlich nach C# mit XNA wechseln soll, weil da vieles sehr einfach ist...

    Ich glaub, ich setz mich sogar jetzt einmal ein bisschen daran!

  8. #8
    Naja, also gibt es dort Klassen und Methoden, Vererbung, Operatoren-Überladung, dynamische Erzeugung von Objekten etc? Letzteres ist wichtig für eine selbstgebaute Linked-List, damit du Listenelemente als Objekte anlegen kannst, vom Typ einer Klasse, welche die Daten beinhaltet.

    Also so Pseudocode-mäßig könnte es so aussehen:

    Klasse Element_Joint {
    Element_Joint *Parent; //Enthält Referenz auf Parent-Element
    Element_Vertex Vertex; //Erstes Listenelement einer Vertex-Liste
    Element_Joint Child; //Erstes Element einer neuen Joint-Liste für die Childs
    };

    Jetzt musst du nur noch ein erstes Element vom Typ Element_Joint erzeugen. Dieses hat als Parent natürlich Null, weil es die höchste Hierachie ist. Vertex kann eine leere Liste sein, wo beim Wichten nachher die Elemente mit Punkten und deren Wichtungswert gefüllt werden. Child ist eine neue Liste vom gleichen Typ Element_Joint, welche die Children enthält.

    Ich bin mir jetzt aber garnicht sicher, ob man bei der Definition der Klasse bereits die Klasse selbst als Datentyp für die Daten innerhalb nutzen kann. Ist sicher Programmiersprachen-Abhängig. Wenn nicht muss man sich etwas anderes überlegen, wie man mehrfach auf seinen eigenen Typ referenzieren kann.

  9. #9
    Ich kenn mich zwar mit free basic nicht aus, aber ich denke, Pointer waeren die beste Idee.

    Alternativ kannst du auch mit Arrays arbeiten und zur Verlinkung Indices speichern. Duerfte aber langsamer sein, und du hast probleme, wenn du mal die Arrays umsortierst.

    Insgesammt ein sehr interessantes Projekt. Wenn es mal fertig ist, stellst du es hoffentlich der Community zur Verfuegung. Koennten sicherlich einige Leute aus dem RM2k Bereich gut zum Animieren von Charas und Monstern verwenden ^__^

  10. #10
    So, sorry, ich war einige Zeit weg, hatte aber mit meinem Laptop etwas weiter gemacht. Hauptsächlich hab ich miene LinkedList verbessert und Sortieralgorithmen hinzugefügt. Das Grundgerüst steht bisher auch, und es funktioniert auch recht gut.

    Jetzt muss ich allerdings erstmal einen simplen Editor erstellen, bei dem man dann die einzelnen Körperteile verschieben und drehen kann.

    Und wenn das funktioniert, kommen die Keyframes hinzu.

    @Luki: Hey, das ginge sogar, dass man die Animation in fertig "gerenderte" Bilder speichert und diese aneinander hängt

  11. #11
    Hey, Lloyd.

    Erstmal fette Respektpunkte von mir
    Ich hätte echt wenig Lust sowas zu machen (na gut ok wir bauen hier ein ein Vertikal-Shooter in Java xD).

    Wenn du das in gerenderte Bilder packst, dann bitte bau einen Algorithmus ein der die Objetke mit einem schwarzen Rand versieht! (evtl mit Option das die Ränder kantig sind und nicht so rund).

  12. #12
    Haha, das mit dem Rand dürfte kein Problem sein. Jensma hat schon ein Programm geschrieben, das nen weißen Rand macht, weil ers so nervig findet, wenn er das pixeln muss

  13. #13
    Ja, ich stelle mir das auch nicht schwer vor, nur das es so kantig wird also so:



    und nicht so:




  14. #14
    Heyho!

    So, also das Projekt ist nicht stehengeblieben, ich hab ab und zu immer mal wieder dran gearbeitet. Nur musste ich recht oft nochmal von vorn anfangen, teils, weil ich bestimmte Sachen nur ausprobiert habe, teils, weil ich irgendwann an einen Punkt geraten bin, wo ich gemerkt habe, dass das Konzept hier und da nicht wirklich gut klappt.

    An so einem Punkt bin ich jetzt mehr oder weniger wieder :'D

    Also ich habe mich für folgenden Aufbau entscheiden:
    -Alles bleibt 2D, in 3D müsste ich mich mit Matrizen und Quaternionen rumquälen, darauf hab ich noch keine Lust
    -ich arbeite mit Joints, die jeweils einen Winkel und einen Offset-Vektor haben. Dazu dann noch ein Verweis auf den Parent, und auf die Childs ( im Moment ein Array bis 10, mehr sollte ein Joint nicht haben müssen )

    So, und wenn ich jetzt zu den Keyframes komme, wirds knifflig.
    Im Prinzip haben die auch nur einen Winkel und einen Offset. Dazu jetzt noch eine Variable für die Zeit.
    Eine Animation ist jetzt einfach nur eine Folge von Keyframes, hab ich hier jetzt mit einer Linked List gemacht.

    Und jetzt kam ich ins grübeln, wie ich denn so eine Animation am besten auf mein Modell anwende. Im Prinzip kann ich einer Animation genau einen Joint zuweisen, auf welchen diese dann angewand wird. Aber um eine Animation des gesamten Modells zu machen, müsste ich für jeden Joint eine Animationskette machen, in denen ja aber alle Keyframes die selbe Zeit haben.

    Ich weiß nicht, mir erscheint das etwas zu umständlich alles. Daher hatte ich überlegt, ob ich nicht einfach jedem Jonit eine Animation zuweise.

    So hatte ichs vorher

    Code:
    class Animation{
       *Keyframe first // verkettete Liste mit Keyframes
       *Joint joint // Referenz auf Joint, auf den Animation angewendet wird
    [...]
    }
    
    class Joint{
        double angle
        Vector offset
    [...]
    }
    So wäre meine jetzige Idee:
    Code:
    class Animation{
        *Keyframe first
    [...]
    }
    
    class Joint{
        
        *Animation animation
    [...]
    }
    Allerdings erscheint mir das auch wieder sehr unflexibel, weil einem Joint genau die eine Animation gegeben wird.

    Meine dritte Idee wäre es, die Animationen so ähnlich aufzubauen, wie die Jonits, also auch in einer Hierarchie. Dabei wäre der Baum exakt so aufgebaut wie das Modell, und die Animationen würde man an der selben Stelle finden wie die Joints. Dann könnte man eine komplette Animation genauso laden und speichern, wie die Joints.

    Ach, ich bin insgesamt einfach etwas durcheinander, vielleicht seh ich den Wald auch vor lauter Bäumen nicht, und ich habs eigentlich schon, erkenns nur nicht oder so. Ich würd nur gern mal eine andere Meinung dazu hören.

    Danke

    Geändert von Teflo (21.12.2010 um 20:54 Uhr)

  15. #15
    Ich würde Variante 2 empfehlen (also das, was als "jetzige Idee" gekennzeichnet ist). Das dürfte am flexibelsten sein und ist sehr einfach zu verarbeiten. In jedem Frame gehst du einmal alle Joints durch, prüfst, zwischen welchen Keyframes du dich befindest und interpolierst. Fertig.

    Variante 3 ist auch nicht schlecht, setzt aber voraus, dass du in jedem Keyframe für alle Joints Werte speicherst. Das ist unter Umständen nicht sooo schön. Insbesondere, wenn du zwei unterschiedlich lange Teilanimationen mischen willst (Beine des Charakters laufen in einem 900 ms Loop, während die Schlag-Animation, die gleichzeitig abläuft, alle 1200 ms geloopt wird.)

    P.S.: Children, nicht Childs. Für den Fall, dass du den Code veröffentlichen willst.

  16. #16
    Mhm, stimmt du hast recht.
    Das hatte ich auch in Planung, dass ich zwei verschiedene Teil-Animationen aufeinanderlegen kann. Also man hat zum Beispiel eine Laufanimation, und legt darüber eine Animation, wie der Charakter schießt / schlägt etc. . Die Beine bewegen sich gleich, nur der Oberkörper wird anders animiert. Daher fällt die 3. Methode definitiv aus.

    Gut, ich werds mit der 2. weiter machen, ich schätze wenn ich dann zum Skinning komme, werde ich nochmal nachfragen müssen, wobei das mit etwas Beeilung vielleicht schon auf der Nato sein wird

    Und ja, das mit Childs / Children war nur ein kurzer Tippfehler, in meinem Code hab ich natürlcih Children stehn xD

    Also damit schonmal danke

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •