Knochenanimation - Matrizen und Berechnungen

7

Wir sind kurz vor dem Abschluss des Projekts, aber kurz vor der Implementierung des Animationssystems.

Unser Kunde entschied sich für "Knochenanimation" - das heißt, ich sollte jede Transformationsmatrix (Matrix4x4 Rotation + Translation) für jeden Frame und für jeden Knochen, den dieses animierte Objekt hat, exportieren.

Objekte in unserem Spiel werden mit 3DS Max Physique Modifier animiert, sodass wir Knochen- / Gewichtungsdaten pro Scheitelpunkt haben. Aber ich werde die Dinge hier vereinfachen, um ein wenig Licht in dieses Thema zu bringen.

Ich möchte diesen Beitrag in 2 Punkte aufteilen, wobei:

  1. Exportieren von Bones-Matrizen für jeden Frame

    • behandelt die richtige Methode zum Exportieren der Knochenpositionen für spätere Animationszwecke, bei denen ich jeden Scheitelpunkt, der von diesem Knochen beeinflusst wird, in Frame X in die Knochenposition "bewegen" und "drehen" muss.
  2. Berechnung der endgültigen Scheitelpunktposition

    • behandelt die richtigen Matrizenoperationen, um die neue Scheitelpunktposition gemäß der Knochentransformation in Frame X zu berechnen.

1. EXPORTIEREN VON KNOCHENMATRIZEN FÜR JEDEN RAHMEN

Verstehe ich richtig, dass ich beim Exportieren des animierten Objekts Folgendes tun sollte:

  1. Nehmen Sie die BONE-Transformationsmatrix in Frame 0 und invertieren Sie diese Matrix

  2. Holen Sie sich die BONE-Transformationsmatrix bei FRAMEx

  3. Multiplizieren Sie 1 * 2, um den Transformationsoffset des BONE bei FRAMEx zu erhalten

[pseudocode]
// Animation export

// For each frame, export bone transformation offset
for(int iFrame = 0; iFrame < vFrames.size(); iFrame++)
{
    // For every bone in the object
    for(int iBone = 0; iBone < vBones.size(); iBone++)
    {
        // Grab transformation matrix for this bone at frame 0 and inverse it
        Matrix3 matBoneMatrixAtStart = pNode->GetObjectTMAfterWSM( 0 );
        matBoneMatrixAtStart.Inverse();

        // Grab transformation matrix for this bone at frame iFrame
        Matrix3 matBoneMatrixAtCurrentFrame = pNode->GetObjectTMAfterWSM( iFrame );

        // Multiply Inversed Transformation Matrix of this bone at frame 0 - with
        //  current frame transformation matrix
        Matrix3 matBoneTransformationOffset = matBoneMatrixAtStart
                                              * matBoneMatrixAtCurrentFrame ;

        // Save matBoneTransformationOffset - vertex will be multiplied by this
        //  matrix for animation purposes
        fwrite(.....)
    }

}
[/pseudocode]

Wird das reichen? Oder fehlt mir hier etwas?

2. BERECHNUNG NEUER VERTICES-POSITIONEN (ENDGÜLTIGE VERTEX-POSITION BEI RAHMEN X)

Später beim Rendern werden Objektscheitelpunkte mit der exportierten Knochentransformationsmatrix für den tatsächlichen Animationsrahmen multipliziert und dann mit dieser gesamten Modelltransformationsmatrix multipliziert, um das Objekt an der richtigen Position innerhalb der Ebene zu platzieren:

[pseudocode]

Update()
{
    // The model transformation matrix describing the position of
    //  the model in the level
    matModelTransformationMatrix


    // Calculate new vertex position according to it's bone transformation offset
    NewVertexPosition = (OriginalVertexPosition * matBoneTransformationOffset[iFrame])
                           * matModelTransformationMatrix;

    // Increment the frame for testing purposes
    iFrame++;
}

[/pseudocode]

Denke ich hier richtig? Wenn Sie also einen Knochentransformationsversatz für Frame X haben und jeden von diesem Knochen betroffenen Scheitelpunkt mit diesem Versatz multiplizieren, sollte dies zu einem Scheitelpunkt führen, der genau wie dieser Knochen transformiert ist, oder?

PeeS
quelle

Antworten:

8

Am besten lesen Sie die Seiten von nVidia, die einige GPU Gems-Artikel enthalten. Es gibt die Schlüsselformel, die ich Ihnen in der folgenden Pseudoantwort kurz erläutern werde:Geben Sie hier die Bildbeschreibung ein

Dies ist , wo Sie den vollständigen Artikel finden, und es ist eine klassische Ressource jetzt. Ich gehe nur davon aus, dass Sie eine Erklärung dieses Prozesses wünschen, die auf vereinfachte Weise erfolgt (so viel ich kann).

Die Formel und ihre Bedeutung:

Sie beginnen mit einem Netz von Scheitelpunkten, dh einer Menge {Pk} von Scheitelpunkten mit Konnektivität. Die Topologie ist Ihnen nicht so wichtig. Ignorieren Sie daher die Konnektivität (das sollte sich nicht verschlechtern, die Verteiler sollten wie Verteiler aussehen, die Topologie erhalten bleiben usw.). In dieser Formel gibt vBindpose die Restposition des Scheitelpunkts des Zeichens an. Dies ist im Objektraum, dh im "Weltraum" des Rahmens dieses Charakters. Jetzt hat jeder Knochen seinen eigenen Rahmen, und die Art und Weise, einen in den Knochenrahmen [i] des Knochens geschriebenen Vektor in den globalen Rahmen des Objekts umzuwandeln , besteht darin, ihn zu multiplizieren mit matrixBindpose [i]. (Stellen Sie sich vor, Sie müssen einen Roboter zusammenbauen, und seine Unterarmscheitelpunkte werden Ihnen in seinem Ellbogenbezugsrahmen gegeben. Der Ellbogen ist mit dem Humerus / Schulterknochen verbunden. Deshalb benötigen Sie diese Transformationen, hauptsächlich, um Scheitelpunktsätze zusammenzusetzen in ein Netz)

Was bedeutet dann INV (matrixBindpose [i]) x vBindpose ? Dies bedeutet, dass Sie die Koordinaten des v- Scheitelpunkts im lokalen Rahmen dieses Knochens [i] erhalten . Warum? Weil sich jeder Knochen seine eigene Version merken kann, wo sich ein von ihm betroffener Scheitelpunkt in Bezug auf seinen eigenen Koordinatenrahmen befindet. Das heißt, jeder Knochen kann Ihnen eine eigene relative Ansicht darüber geben, wo sich ein betroffener Punkt befindet, unabhängig davon, wie andere Knochen diesen Punkt sehen.

Was passiert nun, wenn Sie mit der neuen Knochentransformationsmatrixmatrix [i] multiplizieren ? Erinnern Sie sich vom letzten Punkt an, dass Sie jetzt eine lokale Version des v- Scheitelpunkts haben, dh wie der Knochen [i] denkt, dass der Scheitelpunkt in Bezug auf seinen eigenen Rahmen aussieht. Durch Multiplizieren mit der Matrix [i] erhalten Sie einen Vektor / Scheitelpunkt im globalen / Objektkoordinatenrahmen.

Als nächstes multiplizieren Sie diesen Scheitelpunkt mit dem skalaren Beitrag / Gewicht des Knochens. Was hast du dann Am Ende erhalten Sie eine gewichtete Summe von Vektoren, die im selben Koordinatenrahmen liegen. Deshalb können Sie sie hinzufügen / dh diese Summe über alle Knochen ziehen, die einen Scheitelpunkt beeinflussen.

Ihr Code spiegelt nicht wirklich wider, dass Sie das Verfahren vollständig verstanden haben. Der nVidia-Artikel befasst sich mehr mit der Vorgehensweise über Shader. Deshalb wird davon ausgegangen, dass es höchstens vier Knochen gibt, die einen Scheitelpunkt des Initial- / Bindpose-Netzes beeinflussen können.

Wie Sie sagten, wenn Sie Ihre Startpose einnehmen, die Bindungsposition, dann ist die Matrix [i] x Matrix [i] ^ - 1 die Identitätsmatrix. Das ist in Ordnung, da die Summe gleich _sum (w_i) * vBindpose_ ist. Da vBindpose der im globalen / Objektrahmen geschriebene Vektor ist, ist er bereits zusammengesetzt und in Position. Die Summe dieser Gewichte beträgt konstruktionsbedingt 1 (konvexe Kombination, die aus einem Gewichtsnormalisierungsprozess resultiert - normalerweise vom System durchgeführt, nachdem jedem Scheitelpunkt Gewichte zugewiesen wurden). Mit dieser Formel kann überprüft werden, ob ein Modell korrekt zusammengebaut werden kann (dies wurde normalerweise vom MD5 Doom3 durchgeführtAnimationsmodelllader, wenn ich mich richtig erinnere). Kurz gesagt: Das bedeutet, dass Sie bei jedem Schritt die Berechnungen ein wenig optimieren müssen, damit Sie dort das Ergebnis dieser Lil'ol-Formel berechnen können. Viel Spaß beim Codieren :)

Teodron
quelle
Oh, das ist eine Menge Zeug, das ich jetzt ein paar Mal lesen muss - ich ahnte nicht, dass es so kompliziert ist. Danke für deine Hilfe, das sollte mich zum Laufen bringen ...
PeeS
Willkommen, es ist eigentlich ein ziemlich einfaches Thema, ich habe ein Tutorial dazu gemacht, aber da es nicht auf Englisch war, hilft es nicht, Ihnen das PDF davon zu geben. Ich habe vor, es in einem Video in reinem Englisch zu machen und es auf einem Youtube-Kanal zu veröffentlichen, aber ich habe momentan keine Zeit. Stellen Sie hier in naher Zukunft Ihre Fragen zu diesem Thema. Es ist schön, solche Themen zu diskutieren.
Teodron