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 relative
und SHOULDER absolute
. WRIST local
besteht nur aus Rotation, keine Übersetzung / Skalierung. Das Problem ist, einen Wert dafür zu finden, ELBOW local
dass ...
(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 local
ich 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.
quelle
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 :).elbow_local
weitere 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 verwendetAntworten:
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:
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!
quelle
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.
quelle