Berechnen einer Quaternion, sodass ein Knochen in eine bestimmte Richtung zeigt

7

Um diese Frage zu lösen , habe ich beschlossen, die absoluten (Weltraum-) Richtungen jedes Gelenks in der Quellpose (als normalisierte Einheitsvektoren) herauszufinden und dann die Gelenke des Ziels so zu drehen, dass sie dieser Richtung entsprechen. Das Problem ist, wie berechne ich die Rotationsquaternion so, dass der Knochen (der Vektor vom Gelenk zu seinem Kind) im Weltraum in der angegebenen Richtung liegt.

UPDATE: Hier ist mein aktuelles Denken. Für jeden Knochen lautet die Transformationsmatrix:

(1) absolute transform = local rotation * relative transform to parent in bind pose * parent absolute trasform

Nehmen wir also an, wir haben 3 Gelenke: Schulter -> Ellbogen -> Handgelenk. Wir haben bereits eine absolute Transformation für Schulter und versuchen, die Drehung für Ellbogen so zu berechnen, dass Ellbogen -> Handgelenk in die gleiche Richtung geht wie in der Quellanimation. Aus (1) ergeben sich folgende absolute Transformationen:

(2) ELBOW absolute = ELBOW local * SHOULDER to ELBOW relative * SHOULDER absolute

(3) WRIST absolute = WRIST local * ELBOW to WRIST relative * ELBOW absolute

Durch Substitution erhalten wir:

(4) WRIST absolute = WRIST local * ELBOW to WRIST relative * ELBOW local *
                     SHOULDER to ELBOW relative * SHOULDER absolute

Unsere Konstanten sind: ELBOW to WRIST relative, SHOULDER to ELBOW relativeund SHOULDER absolute. WRIST localbesteht nur aus Rotation, keine Übersetzung / Skalierung. Das Problem ist, einen Wert dafür zu finden, ELBOW localdass ...

(5) normalize(position(ELBOW absolute) - position(WRIST absolute)) = desired direction

(6) ELBOW local consists only of rotations (no translation/scale)

Da wir nun die Länge des Knochens und die gewünschte Richtung kennen, ist es möglich, den Positionsteil von zu schätzen WRIST absolute, aber die Rotation ist unbekannt (und dieses Problem scheint nicht rekursiv zu lösen, AFAICT).

Mein erster Gedanke war, dass WRIST localich es bei der Berechnung von vollständig ignorieren könnte , da es nur für die Rotation bestimmt ist und ich es in der nächsten Iteration der Schleife lösen werde ELBOW local. Die Antwort von Steven Stadnicki unten deutete darauf hin, dass es möglicherweise nicht so einfach ist, da die Ausrichtung des Knochens für das Häuten wichtig ist. Wenn ich dies jedoch an einer Strichmännchen zum Laufen bringen kann, kann ich diese Brücke später überqueren.

Robert Fraser
quelle
2
Hm, wenn ich das richtig verstanden habe: targetDir = normalize (childPos - selfPos) . Wenn Sie ein currDir haben , warum berechnen Sie dann nicht das Quat aus dem Achsenwinkel? Ähnlich wie sie es hier
Teodron
@teodron - Wenn es nur so einfach wäre, aber es gibt 3 andere Matrizen, wird es mit multipliziert. Ich werde die Frage aktualisieren.
Robert Fraser
Eine Frage, weil ich das Gefühl habe, dass Ihre aktualisierte Frage eine offensichtliche Antwort enthält, die Sie nicht wollen: Warum schreiben M = inv(childRelative) * childAbsolute * inv(parentAbsolute) * inv(selfRelative)Sie nicht: wie bei solchen Matrixgleichungen? Was sind die selbstrelativen und kindrelativen Matrizen? Die übliche Art der Transformationsverkettung ist: childTransform = parentToChild * parentTransform . Die anderen Matrizen sind nicht so offensichtlich, was ihr Zweck sein sollte. Das Problem ist interessant und es könnte gut sein, das Rätsel zu lösen :).
Teodron
@teodron - Entschuldigung, ich hätte klarer sein sollen. selfRelative ist die Bindungspositionsmatrix des Elternteils an diesen Knochen (das parentToChild, von dem Sie sprechen). childRelative ist die Bindungspositionsmatrix des aktuellen Knochens für das betreffende Kind. Diese stammen aus dem Skelett und sind fixiert. Was "warum nicht wie eine normale Matrixgleichung lösen" betrifft, zwei Gründe: Erstens muss M nur rotierend sein und ich habe auch nicht die vollständige childAbsolute-Matrix, sondern nur den Positionsteil.
Robert Fraser
1
Kompliziertes Problem, scheint stark unterbestimmt zu sein , so dass kleinste Quadrate / pseudo-inverse Tricks helfen könnten, aber es ist ein Chaos und Sie müssen es numerisch tun. Zunächst fügt nur Ihre Rotationsmatrix 4 Unbekannte hinzu und ist nicht linear, während Sie elbow_localweitere 8 einführen. Das sind 4 Gleichungen mit 8 Unbekannten. Erwägen Sie die Verwendung kinematischer Ketten mit weniger Freiheitsgraden. Haben Sie von der Denavit-Hartenberg- Konvention gehört? Ich habe das mit ziemlich anständigen Ergebnissen verwendet
Teodron

Antworten:

3

Aus Ihrer Beschreibung Ihres Problems geht hervor, dass der Kern der Angelegenheit möglicherweise darin besteht, dass in Ihrer Darstellung derzeit Daten fehlen. Ein Knochen ist nicht einfach der Vektor von einem Gelenk zum nächsten - es ist eine vollständige Transformationsmatrix, die die Ausrichtung des lokalen Rahmens darstellt, entweder in Bezug auf den Weltraum oder in Bezug auf den lokalen Rahmen des nächsten Knochens "die Kette hinauf". . Stellen Sie sich zum Beispiel eine Figur mit einer Narbe am Unterarm vor. Wenn Sie den Vektor vom Ellbogen des Charakters bis zum Handgelenk haben, sehen Sie, wo sich seine Hand befindet, aber er enthält nicht genügend Informationen, um Sie wissen zu lassen, wo sich die Narbe befinden würde - zum Beispiel, ob sie nach oben oder nach unten zeigt. Diese Orientierungsinformationen sollten Teil Ihres Quellgerüsts sein.

Sobald Sie Dinge in Form von vollständigen lokalen Orientierungsrahmen und nicht nur als Richtungsvektoren dargestellt haben, sollte der Rest der Informationen leicht herausfallen. Genau wie Sie in Ihrem Beitrag vorgeschlagen haben, würden Sie Matrix-Inversen verwenden, um die Schichten Ihrer Transformationen abzuziehen und an die saftige Matrix M in der Mitte zu gelangen. Zum Beispiel, wenn Sie haben childAbs = childRel * M * selfRel * parentAbs, dann multiplizieren mit childRel -1 auf die von beiden Seiten links und dann parentAbs -1 * selfRel -1 auf der rechten Seite von beiden Seiten zu bekommen M = childRel - 1 * childAbs * parentAbs -1 * selfRel -1. Beachten Sie, dass das Invertieren eines Matrizenprodukts die Reihenfolge ändert, in der ihre Inversen multipliziert werden, sodass die Reihenfolge hier eine Rolle spielt - (A * B)-1 ist nicht (im Allgemeinen) gleich A -1 * B -1 , sondern B -1 * A -1 .

Sobald Sie Ihre Matrix M haben, sollte es im Web viele Informationen darüber geben, wie Sie sie in eine Quaternion konvertieren können. Wenn Sie Hilfe bei diesem bestimmten Schritt suchen, lassen Sie es mich wissen und ich kann dies mit ein paar Links konkretisieren, aber es scheint, dass Sie noch einige andere Probleme angehen müssen, bevor Sie es überhaupt brauchen Denke darüber nach.

EDIT: Nach ein paar Tagen, um darüber nachzudenken, habe ich diese grobe Beschreibung des Prozesses für den Übergang vom Weltraum zu lokalen Informationen geschrieben. hoffentlich wird dies etwas mehr Licht ins Dunkel bringen.

Ich werde in Form eines entkoppelten Schemas arbeiten, bei dem jeder Knochen aus einer Rotationsmatrix und einer Verschiebung besteht. Die Rotationsmatrix wird an der Wurzel des Knochens angewendet, und die Verschiebung wird in knochenlokalen Koordinaten angegeben. Dies macht zwei wichtige Dinge:

  1. Es ermöglicht die Befestigung mehrerer Knochen an derselben Pfanne, wodurch ein richtiger Skelettbaum ein wenig einfacher wird. Beispielsweise können Schlüsselbeine leicht an einem zentralen Punkt zwischen den Schulterblättern oder Fingerknochen an einem zentralen Punkt am Handgelenk befestigt werden.
  2. Dies bedeutet, dass die meisten Animationen eines Knochens durchgeführt werden können, indem nur die mit diesem Knochen verbundene Rotation geändert wird. Zum Beispiel kann ein Bizeps bewegt werden, indem seine Ausrichtung geändert wird, wodurch die Position des Ellbogens verschoben wird. Tatsächlich haben Knochen häufig eine Verschiebung von (0, 0, L), wobei L die Länge des Knochens ist - das entfernte Ende des Knochens befindet sich direkt entlang der lokalen Z-Achse vom Befestigungspunkt des Knochens.

Dies ist nicht unbedingt der Ansatz, den ich für die Implementierung empfehlen würde, aber er ist der einfachste , um darüber zu sprechen, wie es geht. Während die genauen Ergebnisse nicht direkt auf Ihre Situation anwendbar sind, ist IMHO das Beste: Sie erhalten bessere Chancen zu verstehen, wie die Ableitung funktioniert und wie Sie die genauen Formeln ableiten, die für Ihre eigene Version des Problems gelten.

Einige kurze Definitionen der Größen, mit denen wir arbeiten: Ein hochgestelltes 'w' bezeichnet einen Weltraumwert, während 'l' einen lokalen Wert bezeichnet. Wir werden P für die Position und R für die Rotation verwenden. Zum Beispiel wäre P w -Knochen die Weltraumzielposition eines Knochens (im Gegensatz zu seiner Basisposition, die natürlich die Zielposition seines Elternteils ist), während R l -Knochen die lokale Orientierung des Knochens wäre - das ist, wie es in Bezug auf den Rahmen seiner Eltern gedreht wird.

In Anbetracht dessen können wir nun die Zielposition und -orientierung eines bestimmten Gelenks ableiten - wie einige Kommentare vermuten lassen, ist die Beziehung rekursiv. Insbesondere haben wir

R w Kind = R w Elternteil * R l Kind

und

P w Kind = P w Elternteil + R w Kind * P l Kind

(Diese sagen jeweils: "Die Weltorientierung des Kindes ist seine lokale Orientierung, die sich aus der Weltorientierung seines Elternteils zusammensetzt" und "Die Weltposition des Kindes ist die Weltposition seines Elternteils, die durch seine lokale Verschiebung ausgeglichen wird (übersetzt in die entsprechende) Weltraumkoordinaten) '.)

Vor diesem Hintergrund können wir diese Gleichungen nun lösen, um die Parameter des Knochens - dh R l und P l - in Bezug auf die uns gegebenen Weltraumdaten zu finden. Dies gibt auch einen weiteren Grund, warum wir nicht nur die Position, sondern auch die Weltraumorientierung aller Gelenke benötigen; Es ist ein wesentlicher Bestandteil der Lösung.

Das Finden der lokalen Ausrichtung ist unkompliziert. Wir können einfach beide Seiten unserer Orientierungsgleichung mit der Umkehrung der Weltraumorientierung der Eltern multiplizieren

R l Kind = R w Elternteil -1 * R w Kind

Die lokale Verschiebung ist auch relativ einfach zu berechnen, da wir die Verschiebung im Weltraum und die Transformationsmatrix kennen, um vom lokalen Raum zum Weltraum zu gelangen (was bedeutet, dass wir die Matrix kennen, um in die andere Richtung zu gehen):

P l Kind = R w Kind -1 * (P w Kind - P w Elternteil )

Beachten Sie auch eines: Keine dieser Gleichungen hängt von der lokalen Position oder Ausrichtung des Elternknochens ab, nur von den Weltraumwerten für Eltern und Kind - während sie sich rekursiv fühlen (und von der Berechnung, um die Weltraumwerte für die Knochen zu finden) muss von der Wurzel des Skeletts bis zu seinen Blättern gehen, da es von den Ergebnissen abhängt. Sie können tatsächlich in beliebiger Reihenfolge durchgeführt werden.

Hoffentlich gibt Ihnen dies ein besseres Gefühl dafür, was vor sich geht - es ist leicht, sich in all den Transformationen festzumachen, die herumfliegen. Lassen Sie mich wissen, ob das hilft!

Steven Stadnicki
quelle
Das Quellgerüst besteht aus Rotationen. Die Richtungsvektorsache war nur ein Versuch für mich, sie neu auszurichten. Ich kann die Quellrotation leicht erhalten (relativ zu ihrem eigenen Frame), aber ich weiß nicht, wie mir das helfen wird, da die Quelle eine andere Bindungspose hat. Was den zweiten Teil Ihres Beitrags betrifft, besteht das Problem darin, herauszufinden, was childAbsolute sein wird - ich kenne die Position, aber nicht ihre lokale Rotation.
Robert Fraser
... (würde mich nicht bearbeiten lassen) Für die Berechnung der Rotation des aktuellen Knochens ist es mir nicht unbedingt wichtig, wie die lokale Rotation des Kinderknochens sein wird, nur dass er sich in der richtigen Position befindet.
Robert Fraser
@Fraser Ich mache mir Sorgen, dass wir ein bisschen aneinander vorbeigehen, aber ich verstehe einfach nicht, wie es dir egal ist, wie die lokale Rotation des Kinderknochens sein wird. Diese Daten sind essentiell für jede Häutung Anwendung auf dem Skelett, scheuen die Strichmännchen Animation (oder 2d, aber dann ganz reden wir über ein anderes Problem). Was machst du mit deiner Zielpose, so dass Orientierungen kein Teil davon sind?
Steven Stadnicki
@Fraser Wenn Sie sagen "Ich habe nur Positionen an den Gelenken der Zielpose, keine Ausrichtung" und Sie müssen auch für die Knochen der Zielpose angemessene Ausrichtungen festlegen, dann ist das insgesamt ein weiteres Problem (und ein viel, viel schwierigeres). Aber selbst dort denke ich, dass das Problem viel besser gelöst werden könnte, wenn Sie herausfinden möchten, wie Sie die Ausrichtung aus Ihren Zielposendaten herausholen können, anstatt selbst eine „vernünftige“ Ausrichtung zu erstellen.
Steven Stadnicki
Ich habe die Frage neu geschrieben, um klarer zu machen, was ich erreichen möchte. Hier ist ein Video von meinen Fortschritten vor 2 Wochen: youtube.com/watch?v=H6Qq37TM4Pg ... Danke für all deine Hilfe, Alter.
Robert Fraser
2

Wenn ich das richtig verstanden habe, speichern Sie die gesamten Scheitelpunkte der Skelettknochen in einer Matrix. Ich denke, Ihr Problem hängt mehr mit der Art und Weise zusammen, wie Sie die Knochen speichern, als mit den Quaternionen selbst.

Ich werde versuchen zu erklären, was ich meine:

Da Sie im Grunde das Ergebnis der Rotation haben (ein gedrehter Knochen, der als Modell verwendet werden soll) und die Quaternion kennen möchten, die dieses Ergebnis für andere Knochen erzeugen würde, können Sie die Knochen nicht als Vektoren speichern, anstatt zu generieren eine Matrix?

Sie könnten einen Knochen als Vektor aus 2 Punkten (Kopf, Schwanz) speichern. Da Sie es drehen, ist Kopf der Drehpunkt und Schwanz dreht sich um eine beliebige Achse. Das ist die Aufgabe eines Quaternions.

Da Sie Knochen A in einer "ausgeruhten" Position haben und die Richtung von Knochen B anpassen möchten, müssen Sie den Rotationsbetrag Alpha und die Achse kennen. Recht?

Wenn Sie den Winkel zwischen den beiden Knochenvektoren A und B ermitteln, finden Sie Alpha, und das normalisierte Ergebnis des Kreuzprodukts von AxB ergibt die Achse.

Das einzige, was für Sie komplizierter wird, ist, dass Sie den Knochenvektor aus der zuvor verwendeten Matrix extrapolieren müssen, damit Sie die Knochen möglicherweise einfach als Vektoren (Punktepaar) speichern können, anstatt eine Matrix zu erstellen.

Da Sie im Grunde genommen einen Knochen in Bezug darauf drehen, wie sein Elternteil gedreht wurde (das habe ich aus Ihrem Code erhalten), könnten Sie das alles wahrscheinlich einfach ignorieren.

Da Sie mit der Position eines anderen Knochens übereinstimmen möchten, wissen Sie bereits, dass diese Position legitim ist, sodass nicht alle Dinge mit relativer Rotation erforderlich sein sollten.

Dunkle Flügel
quelle
Das Problem beim Speichern als Vektoren ist die Interpolation zwischen Frames oder das Mischen mehrerer Animationen.
Robert Fraser
Ich kann die Antworten anderer Benutzer (noch) nicht kommentieren. Wenn Sie mehr Daten als nur 2 Punkte benötigen, speichern Sie diese auf eine Weise, die zu Ihnen passt. Beide Antworten, die Sie bisher erhalten haben, weisen auf dasselbe Problem hin: Entweder fehlen Daten oder Sie verwenden ein Format, das Ihr Problem verursacht. Wenn ein Knochen Rotation und Translation enthält, können Sie einfach die entsprechenden Informationen speichern, ohne sich mit einer vollständigen Matrix zu befassen, und so die gesamte Konvertierung vermeiden. Wenn nur Quaternionen und 2-3 Punkte pro Knochen verwendet werden, hängt die Position des Kindes nur von der des Elternteils ab, sodass das System für sich selbst sorgen sollte.
Darkwings
Der gesamte Zweck besteht darin, Animationen von einem Skelett zum anderen neu auszurichten, sodass die Ergebnisse wie von einem Künstler erstellte Animationen verklagt und mit prozeduralen und von Künstlern erstellten Animationen gemischt werden können. Die Daten, die ich speichere, sind eine Rotationsquaternion für jeden Knochen relativ zu seinem Elternteil für jeden Frame. Dies funktioniert bereits für importierte Animationen. Ich möchte die Art und Weise, in der ich die Ergebnisanimationen speichere, nicht ändern. Dieser Schritt ist vollständig Teil der Pipeline. Ich möchte, dass das Endergebnis genauso funktioniert (und mit anderen Animationen interagiert).
Robert Fraser
Ich habe das Video gesehen. Ich bin immer noch davon überzeugt, dass Sie Ihr Leben immer noch komplizieren, um eine Rotation relativ zu einer bekannten Achse (relativ zum Elternknochen) einfach zu speichern. Ich verstehe, dass der Grund, warum Sie eine Nur-Rotation-Matrix wünschen, darin besteht, unerwünschte Übersetzungen zu verhindern, die zu einer ungültigen Eltern-Kind-Position führen. Etwas, das sowieso nicht passieren könnte, wenn Sie den Elternknochen als Achse verwenden würden, die nur mit Quaternionen gebunden ist. Andernfalls müssten Sie endlos von Matrix zu Quaternion konvertieren und dann erneut Matrix. Kurz gesagt, ich teile Steven Stadnickis POV, wenn er sagt, dass es nicht nur ein mathematisches Problem ist.
Darkwings