Bruchteile von Bits in einer gepackten Rotation
Eine Einheitsquaternion besteht aus vier Zahlen, deren Quadrate zusammen eins ergeben. Ken Shoemake führte sie im Jahr 1985 in die Computergrafik ein, um Drehungen zu speichern und zu interpolieren, und heute werden sie überall eingesetzt, wo eine Drehung festgehalten werden muss. Ein animiertes Skelett speichert eine solche Quaternion für jedes Gelenk in jedem Keyframe. Ein Mesh kann die Tangentenbasis jedes Vertex als eine Quaternion speichern, für Normal Mapping. In einer Szene aus Gaussian Splatting erhält jede ihrer Millionen Gaußfunktionen eine Ausrichtung, und auch das ist eine Quaternion. Speicher und Bandbreite sind es eher als Rechenoperationen, die diese Programme bremsen. Ein Byte, das bei einer Drehung gespart wird, ist millionenfach gespart.
Die vier Zahlen sind nicht unabhängig voneinander. Wenn drei davon bekannt sind, ist die vierte bis auf ihr Vorzeichen festgelegt. Ein Kompressor speichert daher drei Zahlen sowie einen kleinen Index, der Karte genannt wird und anzeigt, wie die vierte Zahl wiederhergestellt werden kann. Üblich ist die Smallest-Three-Methode: Man lässt die betragsgrößte Komponente weg und notiert, welche es war und ihr Vorzeichen. ozz-animation arbeitet auf diese Weise, genauso wie die glTF-Erweiterung EXT_meshopt_compression sowie die Splat-Formate SPZ und SOG.
In Compression of Uniformly Distributed Unit Quaternions, das im Oktober 2026 auf arXiv veröffentlicht wurde, teilen Carsten Faber, Bastian Kuth, Rinaldo Schuster, Daniel Pauls und Quirin Meyer von der Hochschule für angewandte Wissenschaften Coburg sowie von AMD stattdessen durch die größte Komponente. Dadurch wird die Rotation auf die Oberfläche eines vierdimensionalen Würfels gebracht. Eine kubische Verzerrung mit a·x3 + (1 − a)·x und einem Wert von a = 0,373964 verteilt die Abtastwerte dann gleichmäßiger, als es der bloße Würfel tun würde. Die Autoren nennen das Ergebnis ℓ∞cub. Hier heißt es der Würfel-Codec. Vier Möglichkeiten für die größte Komponente zusammen mit zwei Vorzeichen ergeben acht Karten, und acht Karten passen in drei Bits.
Bits, die nicht durch drei aufgehen
Man legt eine solche Rotation in ein 32-Bit-Wort. Die Karte belegt drei Bits, wodurch 29 Bits für drei Zahlen übrig bleiben, also etwa 9,67 Bits pro Zahl. Bitfelder arbeiten mit ganzen Bits. Jede Zahl erhält 9 Bits, was 512 Stufen bedeutet, wobei zwei Bits des Wortes ungenutzt bleiben. Eine andere Möglichkeit besteht darin, einer Zahl 10 Bits zuzuweisen und den anderen weniger, sodass eine Achse der Rotation feiner gespeichert wird als die anderen.
Die Arbeit packt das Wort als einzige Ganzzahl in ein Stellenwertsystem mit gemischten Basen, wobei jede Stelle ihre eigene Basis hat. Die Karte ist dabei eine Stelle zur Basis 8. Jede der drei Zahlen ist eine Stelle zur Basis U. Beim Packen wird dreimal mit U multipliziert und addiert. Beim Entpacken nimmt man dreimal den Rest und teilt, und was am Ende übrig bleibt, ist die Karte. Die größte Zahl U, bei der 8·U3 weiterhin unter 232 passt, beträgt 812. Jede Achse erhält 812 Stufen und nicht 512, wobei der Abstand benachbarter Abtastwerte auf etwa 0,63 des Bitfeld-Abstands schrumpft. Bastian Kuth und Quirin Meyer hatten bereits 2021 dasselbe Verfahren für Vertex-Blend-Gewichte verwendet. Die Autoren vergleichen es mit asymmetrischen Zahlensystemen mit einer gleichmäßigen Verteilung.
Was die Division kostet
Eine Division klingt für einen Dekoder langsam. Hier ist jede Basis eine Konstante, weshalb der Compiler jede Division sowie jeden Rest in eine Multiplikation und eine Verschiebung umwandelt. Wenn die nach der Karte verbleibenden Bits gleichmäßig durch drei teilbar sind, wie bei 24 und 48 Bits mit drei Kartenbits, ist überhaupt keine Ganzzahldivision nötig. Die Autoren maßen die Zeit für einzelne Dekodierungen mit dem Hardware-Zykluszähler einer AMD Radeon RX 7900 XTX. Ihr 32-Bit-Dekoder benötigte 111 Zyklen. Eine sphärische lineare Interpolation zwischen zwei Quaternionen dauerte auf derselben Grafikkarte 171 Zyklen. Die MPEG-4-Methode, bei der der Würfel mit einem Tangens verzerrt wird, benötigte 273 Zyklen, da der Tangens im Compiler zu einem Sinus geteilt durch einen Kosinus wird. Die kubische Verzerrung wird mit dem Schritt kombiniert, der eine Stufe wieder in eine Zahl umwandelt, und beides zusammen kostet drei Fused-Multiply-Add-Operationen.
Das Vorzeichen, das nichts trägt
Eine Quaternion und ihr Negatives beschreiben dieselbe Drehung. Ein Codec kann bei jeder Drehung das Vorzeichen so wählen, dass die größte Komponente positiv ist, und muss das Vorzeichen dann nicht mehr speichern. Einige Animationsbibliotheken tun das. ozz-animation hingegen nicht. Für einen Schlüssel verwendet sie 48 Bit: 15 Bit für jede der drei Zahlen, zwei Bit für die Karte und ein Bit für das Vorzeichen. Ohne das Vorzeichen bleiben 46 Bit übrig. Drei gleich große Bitfelder können diese 46 Bit nicht teilen, weshalb die Bibliothek das Vorzeichen sowie die 15 Bit pro Zahl beibehält. Als eine einzige Ganzzahl geben dieselben 46 Bit jeder Achse 41.285 Stufen anstelle von 32.768, was 246/3 abgerundet entspricht. Ein zurückgewonnenes Bit, auf drei Achsen verteilt, bringt jeder Achse den Faktor 21/3, etwa 1,26.
Das Testmaterial bestand aus dem Mixamo-Korpus mit insgesamt 34.884.287 Keyframes. Der ursprüngliche ozz-animation-Codec wies einen maximalen Fehler von 0,00909° auf. Der Würfel-Codec, der weiterhin 15 Bit pro Zahl verwendet und das Vorzeichen speichert, verringerte diesen Wert auf 0,00203°. Durch Weglassen des Vorzeichens sank der Fehler auf 0,00161°, 5,6-mal weniger als zu Beginn. Ein 40-Bit-Schlüssel ohne Vorzeichen ergab einen Fehler von 0,01020°, was 12 Prozent über dem Wert des 48-Bit-Formats liegt. Er sparte pro Schlüssel ein Byte ein, was insgesamt 33,3 MiB im gesamten Korpus ausmacht. Renderings eines Drachen, der auf beide Arten animiert wurde, zeigten einen vergleichbaren Bildfehler. Das Sampling von 1024 geskinnten Figuren lief 12 bis 16 Prozent schneller als mit dem ursprünglichen Codec.
Eine Tangentenbasis ist eine Drehung, die auch gespiegelt sein kann, da Texturkoordinaten entlang einer Naht umgekehrt werden können. Das Bit, das das Vorzeichen nicht mehr braucht, kann diese Händigkeit speichern. CryEngines QTangents, die 2011 vorgestellt wurden, bestanden aus vier 16-Bit-Komponenten und versteckten die Händigkeit im Vorzeichen der vierten Komponente, indem diese etwas von null weggeschoben wurde, damit das Vorzeichen die Rundung übersteht. Beim Würfel-Codec mit 16 Bit pro Tangentenbasis lassen acht Karten 13 Bit für drei Zahlen übrig. Bitfelder gäben jeder Zahl 16 Stufen. Eine einzige Ganzzahl gibt 20 Stufen und nutzt dabei 64.000 der 65.536 möglichen Codes. Die Arbeit gibt das als 15,97 genutzte Bit an.
| Was gespeichert wird | Bits | Karten | Bitfelder | Eine Ganzzahl |
|---|---|---|---|---|
| Rotation mit ihrem Vorzeichen | 32 | 8 | 512 | 812 |
| Animationsschlüssel ohne Vorzeichen | 48 | 4 | 32.768 | 41.285 |
| Animationsschlüssel ohne Vorzeichen | 40 | 4 | 4.096 | 6.501 |
| Tangentenbasis mit Händigkeit | 16 | 8 | 16 | 20 |
Gaussian-Splats werden auf dieselbe Weise behandelt, da eine Quaternion und ihr Negatives dieselbe Gaußfunktion liefern. Der Renderer von Rijsdijk und seinen Kollegen packt die Geometrie jeder Gaußfunktion in 128 Bit, davon 30 Bit für die Rotation, und komprimiert diese Rotation mit einer Exponentialabbildung. Auf drei Szenen aus Mip-NeRF 360 erreichte die Exponentialabbildung mit 30 Bit ein Spitzen-Signal-Rausch-Verhältnis von 45,90 dB. Der Würfel-Codec erreichte bei 24 Bit 45,83 dB. Bei 16 Bit lag er um 6,67 dB vorn. Das Dekodieren der Rotationen dauerte in jedem Fall etwa 0,5 ms pro Frame, im Vergleich zu 11,8 ms für das Rendern.
Ungerade Stufenzahlen und die Untergrenze
Ein Bitfeld hat stets eine Zweierpotenz an Stufen, also eine gerade Zahl. Der Quantisierer der Arbeit platziert seine Abtastwerte in den Mittelpunkten gleich großer Schritte im Bereich von −1 bis 1, wodurch bei einer geraden Anzahl kein Abtastwert auf Null fällt. Bei Null liegt die Identitätsrotation, in der Mitte ihrer Karte, und Animationen enthalten viele solcher Identitätsrotationen. Ein Bitfeld gibt sie nie exakt zurück. Bei einer ungeraden Anzahl liegt ein Abtastwert auf Null, und mit einer einzigen Ganzzahl kann der Codec eine ungerade Anzahl wählen. Die Autoren nennen das trivial. Ihre Fehleranalyse berücksichtigt es jedoch nicht.
Unter all dem liegt eine Untergrenze. Die Arbeit zeigt, dass kein Code mit 2k Zuständen seinen größten Fehler unter etwa 96° mal 2−k/3 halten kann. Bei großen Bitbudgets benötigt der Würfel-Codec etwa 1,5 Bits mehr als diese Schranke. Die Schranke setzt voraus, dass sich die Rotationen gleichmäßig über alle Orientierungen verteilen. Eine Animationsspur, die nur wenig dreht, kann mit einem auf diese Spur abgestimmten Bereich besser abschneiden, und genau das tut die Animation Compression Library. Jeder Code hat hier die gleiche Länge, im Gegensatz zur Huffman-Stufe der JPEG-Kompression. Deshalb kann ein Shader jede einzelne Rotation lesen, ohne die vorherigen dekodieren zu müssen.
Quelle
Carsten Faber, Bastian Kuth, Rinaldo Schuster, Daniel Pauls und Quirin Meyer, Compression of Uniformly Distributed Unit Quaternions, arXiv, Oktober 2026, DOI 10.48550/arXiv.2610.22052, veröffentlicht unter der Lizenz CC BY 4.0. Jede Zahl, Zeitangabe und Schranke in dieser Notiz stammt daraus.
