Registriert: Mi Aug 14, 2013 21:17 Beiträge: 588
Programmiersprache: C++
Moinsen, beim Schreiben des Artikels Dual Quaternion bin ich gerade ins Grübeln gekommen. Die skeletale Animation läuft bei mir derzeit mit dualQuats. Wenn ich dort einen Vertex transformieren möchte, sind das im Grunde drei Schritte: 1. Von der Position des Vertex wird die absolute Position des Joints in Ruhe-Pose (T-Pose) abgezogen, um eine Position relativ zum Joint zu bekommen. 2. Diese relative Position wird rotiert. 3. Anschließend wird die aktuelle absolute Position des Joints aufaddiert.
Das sind also 2 Translationen und eine Rotation. Der Translationsvektor im 3. Schritt ist aber ein völlig anderer als der im 1. Schritt. Bei dualQuats ist das kein Problem, weil man die verketten kann wie Matrizen und somit alle 3 Schritte in ein dualQuat packen kann.
Wie u.a. diese Diskussion vor einigen Monaten ergeben hat, setzen viele von euch aber keine dualQuats, sondern eine Kombination aus Quaternion und Translationsvektor ein. Wie schafft ihr es da, mit nur einem Translationsvektor auszukommen?
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Ich frage mich/euch, wie man das mit einem Quaternion und nur einem Translationsvektor realisieren soll. Im Artikel Boneanimation per Vertexshader wird der erste Schritt offenbar komplett weggelassen. Meiner Meinung nach müsste man dem Vertexshader zwei Translationsvektoren pro Joint übergeben - oder habe ich was übersehen?
Falls meine Frage immer noch unverständlich ist, bitte nachfragen! Die Erkenntnisse aus diesem Thread werden natürlich ins Wiki miteinfließen. Sorry, dass ich so ungeduldig bin, aber nächste Woche werde ich möglicherweise keine Zeit finden, am Wiki zu arbeiten.
Vielen Dank schonmal für eure Antworten!
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Die beiden Verschiebungen sollten doch zusammengefasst werden können. Rein Geometrisch betrachtet kann man den durch die 3 Operationen erzeugte Transformation auch mit 2 Operationen erzeugen. Dafür müsste man einfach die erste Verschiebung mit der umgekehrten Rotation multiplizieren und dann mit dem anderen Verschiebungsvektor multiplizieren. Auf jeden Fall scheinen mir die Dual Quaternions mathematisch wesentlich eleganter zu sein. Bei der Rotationsquaternion-/ Verschiebungsvariante kommt es unter anderem darauf an, ob erst verschoben wird und dann rotiert oder andersrum. Außerdem lassen sich mehrere Solcher Transformationen nur komplizierter zusammenfassen, wie du auch schon festgestellt hast.
Ich habe bis jetzt nur oberflächliches Wissen ober Charakteranimation, aber was ich mich da grundsätzlich dazu frage ist, wozu du Verschiebung überhaupt dienen soll. Zwischen den Bones sind doch Kugelgelenke, die nur gedreht werden können und nicht verschoben. Deshalb sehe ich schon mal gar keinen Sinn darin, irgendetwas verschieben zu wollen.
Zuletzt geändert von OpenglerF am Mo Jan 06, 2014 14:22, insgesamt 1-mal geändert.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
glAwesome hat geschrieben:
Wie u.a. diese Diskussion vor einigen Monaten ergeben hat, setzen viele von euch aber keine dualQuats, sondern eine Kombination aus Quaternion und Translationsvektor ein. Wie schafft ihr es da, mit nur einem Translationsvektor auszukommen?
Ich mache die Bone-Animation zwar nicht mit Quaternionen, sondern nur mit altmodischen Matrizen und habe derzeit auch nur ein einziges winziges Testprogramm mit Bones laufen, weil das Thema "Animation" im Augenblick nicht meine volle Aufmerksamkeit hat. Aber das Prinzip sollte ja das Gleiche sein, egal ob es sich um Matrizen, Quaternionen oder Duale Quaternionen handelt.
Das, was ich Dir hier erzähle, habe ich von einer sehr informativen australischen Website, die es lange nicht mehr gibt (seufz), und etliches davon musste ich mir auch selber zusammenreimen; aber so, wie ich es hier beschreibe, funktioniert meine Testanwendung und es sieht auch richtig aus.
Ich betrachte das Animations-Problem etwas anders als Du, und mit einem kleinen, naja, "Trick" ist der OffsetVektor immer gleich. Ich zerlege das Problem dazu in zwei Teile:
(Anmerkung: Der "OffsetVector" ist der Positionsvektor des jeweiligen Gelenks in der BindPose, und der ist für ein Gelenk immer gleich)
Teil 1: Herstellen der lokalen Transformations-Matrizen (*LTM*) der Gelenke:
*Das Gelenk wird zum Koordinatenursprung verschoben (OffsetVector = negative Gelenkposition; Space = Model-Space) *Die LOKALE Rotation ist repräsentiert durch eine vorhandene RotationsMatrix (ich kümmere mich jetzt nicht darum, wo man diese herbekommt, es genügt irgendeine) *Das Gelenk wird nach der Rotation wieder mit dem *positiven* Offset-Vector in seine BindPose-Position zurück verschoben.
Diese drei Transformationen kann man in eine einzige Matrix verpacken. Wenn man das Sonnensystem simulieren wollte und die einzelnen Planeten rotieren möchte, macht man im Prinzip das Gleiche; Ich nenne diese Funktion in meiner eigenen Math3D-Lib "MatrixRotateLocal" auf Deutsch: Rotieren am Stand :
Code:
Function MatrixRotateLocal(Const AOffset: TVector3F;
Const Angle:Single;
Const Axis: TVector3F): TMatrix16F;
Var
MatInvers,MatRevers,MatRotation: TMatrix16F;
Begin
MatInvers:= MatrixShift(VectorInvers(AOffset));
MatRotation:= MatrixRotate(Angle,Axis);
MatRevers:= MatrixShift(AOffset);
// Order: 1.Invers, 2.Rotate, 3.Revers
Result:= MatrixMultiply(MatRevers,
MatrixMultiply(MatRotation,MatInvers));
End;
Teil 2: Herstellen der kombinierten Transformations-Matrizen (*CTM*) der Gelenke: Vom Haupt-Gelenk her wird nun die jeweilige kombinierte Gelenks-Matrix folgendermaßen hergestellt:
Wobei im ersten Gelenk ist CTM = LTM. Achtung auf die Reihenfolge bei der Matrixmultiplikation: LTM muss die erste sein.
Mit einer Baum-mäßigen Rekursionsfunktion schafft man Teil 2 mit höchstens 2 Zeilen Code.
Ich schätze jetzt mal (ich weiß es aber nicht), dass in den üblichen Animations-Formaten nur mehr die CTMs vorhanden sind, denn der OffsetVektor aus Teil 1 wird vollkommen "verschluckt", daher bekommt der Shader m.E. eben nur mehr ein Model(View)-Matrix-Array übergeben. Der Translationsvektor aus Deiner Frage ist möglicherweise eine Verschiebung des Modells im World-Space, es könnte sich also einfach um ein Missverständnis handeln.
Viele Grüße Traude
PS: @OpenglerF: das Hin- und Herverschieben braucht man, damit die Rotation überhaupt möglich gemacht wird, denn Rotieren funktioniert nur am Koordinatenursprung
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Traude hat geschrieben:
Das, was ich Dir hier erzähle, habe ich von einer sehr informativen australischen Website, die es lange nicht mehr gibt (seufz)
Hast du noch die URL? Wenn ja könnte archive.org helfen.
grüße
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ich habe nach längerem Suchen die URL der Website gefunden und habe es auf archive.org versucht, aber dort wurde zwar die Website registriert aber der relevante Inhalt war offenbar nicht mehr gespeichert. Lt. meinen eigenen Aufzeichnungen habe ich das in 2006 heruntergeladen; ist schon ziemlich lange her, dass ich mich mit Bone Animation beschäftigt habe.
Ich habe aber nicht nur die URL gespeichert, sondern auch ein Exzerpt aus dem Inhalt der Website als RichText-File. Wenn jemand interessiert ist, kann ich das zur Verfügung stellen. Allerdings - heute gibt es glaub ich viel bessere Infos über Bone Animation im Web als im Jahr 2006.
Registriert: Mi Aug 14, 2013 21:17 Beiträge: 588
Programmiersprache: C++
Danke für die doch plötzlich sehr vielen Antworten!
OpenglerF hat geschrieben:
Die beiden Verschiebungen sollten doch zusammengefasst werden können.
Jetzt wird's mir klar. Ist ja im Prinzip das gleiche wie bei Matrizen. Man kann Translationsmatrix * Rotationsmatrix * Translationsmatrix rechnen und aus dem Resultat den Rotations- und Translationsteil extrahieren.
OpenglerF hat geschrieben:
Ich habe bis jetzt nur oberflächliches Wissen ober Charakteranimation, aber was ich mich da grundsätzlich dazu frage ist, wozu du Verschiebung überhaupt dienen soll. Zwischen den Bones sind doch Kugelgelenke, die nur gedreht werden können und nicht verschoben.
Die Verschiebung, von der ich sprach, dient auch nicht dazu, eine Gelenk zu verschieben, sondern um um den richtigen Punkt zu drehen. Jedes Gelenk dreht ja um seine Position und die ändert sich während der Animation. Daher müssen die Vertices vor und nach der Rotation entsprechend verschoben werden, da man mit einem Quaternion/einer Rotationsmatrix immer nur um den Ursprung drehen kann. Andererseits gibt es durchaus Anwendungen, wo Gelenke nicht nur gedreht, sondern richtig transliert werden müssen. Mit skelettaler Animation lassen sich ja nicht nur Menschen, sondern z.B. auch Maschinen (Kolben) animieren.
@Traude: Was du beschreibst, scheint mir sehr ähnlich zu meinem Tutorial zu sein. Nur dass du erst die drei Transformationen berechnest und dann die absoluten Transformationen rekursiv bestimmst. Ich mache es genau andersherum - sollte aber beides funktionieren.
Die Erkenntnisse aus diesem Thread werde ich dann voraussichtlich nächstes Wochenende ins Wiki überführen (scheiß Uni).
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
glAwesome hat geschrieben:
@Traude: Was du beschreibst, scheint mir sehr ähnlich zu meinem Tutorial zu sein. Nur dass du erst die drei Transformationen berechnest und dann die absoluten Transformationen rekursiv bestimmst. Ich mache es genau andersherum - sollte aber beides funktionieren.
Dann empfehle ich Dir, meinen Beitrag oben nochmals zu lesen, denn das, was ich oben beschrieben habe, kann man gar nicht umkehren. Einfach nur so drüberlesen ist in diesen Fall nicht erlaubt. Es gibt Code, der auf den ersten Blick ganz harmlos aussieht, aber der es in sich hat. Er hätte sich ein wenig mehr Aufmerksamkeit von Dir verdient.
glAwesome hat geschrieben:
Die Verschiebung, von der ich sprach, dient auch nicht dazu, eine Gelenk zu verschieben, sondern um um den richtigen Punkt zu drehen
Das kann nicht sein, denn die Gelenks-Matrix, die am Ende herauskommt, muss für *alle* Punkte gelten, die diese Gelenks-Matrix benutzen.
glAwesome hat geschrieben:
Daher müssen die Vertices vor und nach der Rotation entsprechend verschoben werden
Nein, es wird bloß das Gelenk hin und zurück verschoben. Darum geht's ja eigentlich.
glAwesome hat geschrieben:
Andererseits gibt es durchaus Anwendungen, wo Gelenke nicht nur gedreht, sondern richtig transliert werden müssen. Mit skelettaler Animation lassen sich ja nicht nur Menschen, sondern z.B. auch Maschinen (Kolben) animieren.
Ja, natürlich, aber dann nimmt man in meinem Teil 1 einfach eine Translationsmatrix oder auch eine kombinierte Translations/Rotationsmatrix. In Deinem Fall das entsprechende duale Quaternion.
Es geht mir jetzt nicht wirklich bloß darum, recht zu haben, denn ich sehe mir Deine Beiträge schon eine Weile an, eben weil Du Dich mit Animation beschäftigst, was mich selber ungeheuer interessiert, und was hier auf DGL verflixt selten ist. Du hast praktisch bewirkt, das ich jetzt wieder öfter einen Blick auf die DGL-Website mache.
Traude Deren Erfahrung mit Skeletaler Animation zwar schon lange her ist, die sich damals aber sehr lange und intensiv damit beschäftigt hat.
Registriert: Mi Aug 14, 2013 21:17 Beiträge: 588
Programmiersprache: C++
Traude hat geschrieben:
das, was ich oben beschrieben habe, kann man gar nicht umkehren.
Ich habe mir nochmal die Zeit genommen und deinen Beitrag ganz genau durchgelesen. Und glaub mir: Man kann die Reihenfolge vertauschen. So funktioniert es ja bei mir.
Der Punkt ist der: Du baust in deine lokalen Matrizen bereits die beiden Translationen (um den negativen und positiven Offsetvektor) mit ein. Da du dies bereits in der lokalen Matrix tust, kannst du für beide Translationen den gleichen Vektor nehmen (zwar mit anderem Vorzeichen, sonst aber gleich). Danach erst verkettest du die Transformationen. Bei der Verkettung kommt es zu einer Verschiebung der Rotationscenter. Denn wenn du beispielsweise deinen Arm hebst (das Schultergelenk drehst) ändern sich ja die Positionen von Hand- und Ellenbogengelenk. Da du die Verkettung aber als letztes ausführst braucht dich das bei deinem Ansatz nicht zu interessieren.
Ich gehe den anderen Weg: Ich bestimme erst die absoluten (= nicht lokalen, "verketteten") Rotationen und Rotationscenter. D.h. ich multipliziere die Rotationen rekursiv vom Wurzelknoten bis zum Blatt durch. Die Translationen werden - nach der Anwendung der jeweiligen absoluten Rotation - addiert. Das heißt, nach dem ersten Schritt weiß ich für jeden Joint, welche Orientierung er hat und an welcher Stelle er sich befindet. Erst jetzt baue ich die Matrizen/DualQuats. Da sich die Positionen der Gelenke inzwischen verschoben haben, kann ich nicht wie du um -Offset translieren, die Rotation anwenden und wieder um Offset translieren. Das würde nicht funktionieren. Ich benötige nämlich jetzt zwei völlig verschiedene Translationsvektoren. Ich muss nämlich erst die Position des Gelenks in der Standardpose abziehen, dann rotieren und anschließend die im ersten Schritt berechnete aktuelle Position des Gelenks addieren.
Da ich bei meinem Ansatz zwei verschiedene Translationsvektoren habe, habe ich mich gefragt, wie man mit nur einem auskommen soll - daher dieser Thread.
Ich hoffe, ich hab's vertsändlich formuliert bekommen. Sowas ist immer einfacher zu erklären, wenn man es sich an einem Live-Objekt veranschaulichen kann. Die anderen Punkte, an denen du mir widersprochen hast, sollten nun hoffentlich klar sein.
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ich habe mir Deinen letzten Betrag auch genau durchgelesen. Ja, Du kannst das Ganze natürlich umkehren insofern, als Du zuerst den Gelenksbaum berechnest und erst anschließend die lokalen Matrizen. Aber ganz schaffst Du es doch nicht, weil Du jetzt den neuen Verschiebungsvektor erst berechnen musst. Wenn Du - wie Du gesagt hast - den zweiten Verschiebungsvektor Punkt-weise berechnest, ist das ein relativ hoher Berechnungsaufwand.
Gibt es einen Grund warum Du gerade diese Berechnungsweise gewählt hast? Vielleicht liegt es ja an den Dual Quaternions?
Registriert: Mi Aug 14, 2013 21:17 Beiträge: 588
Programmiersprache: C++
Traude hat geschrieben:
Du kannst das Ganze natürlich umkehren insofern, als Du zuerst den Gelenksbaum berechnest und erst anschließend die lokalen Matrizen.
Ich berechne keine lokalen Matrizen. Da der Gelenkbaum nach dem ersten Schritt die absoluten Positionen und Rotationen enthält, kann ich daraus direkt die absoluten/globalen/verketteten (such dir einen Begriff aus) Matrizen bzw. DualQuats berechnen.
Traude hat geschrieben:
Wenn Du - wie Du gesagt hast - den zweiten Verschiebungsvektor Punkt-weise berechnest, ist das ein relativ hoher Berechnungsaufwand.
Wo habe ich gesagt, dass ich ihn punktweise berechne? 1. Transformation: Translation um -(Position des Joints in T-Pose) 2. Transformation: Rotation 3. Transformation: Translation um die aktuelle Position des Joints
Das alles wird in eine Matrix/ein DualQuat gesteckt. Beide Translationsvektoren sind nicht vom jeweiligen Vertex abhängig, sondern nur vom Joint.
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
glAwesome hat geschrieben:
Wo habe ich gesagt, dass ich ihn punktweise berechne?
Ich habe diese Passage von Deinem ersten Beitrag so interpretiert, insbesondere den Punkt 1:
glAwesome hat geschrieben:
1. Von der Position des Vertex wird die absolute Position des Joints in Ruhe-Pose (T-Pose) abgezogen, um eine Position relativ zum Joint zu bekommen. 2. Diese relative Position wird rotiert. 3. Anschließend wird die aktuelle absolute Position des Joints aufaddiert.
Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.