EnglishРусскийTürkçeDeutschFrançais О библиотеке · RSS
WebInterface.org
WebInterface.org

Заметки о рисунках, печатных изданиях, фотографиях и изображениях, созданных с помощью компьютера.

Главная · Трехмерная графика · Дробные биты в упакованном повороте

Дробные биты в упакованном повороте

Единичный кватернион это четыре числа, квадраты которых в сумме равны единице. В 1985 году Кен Шумейк ввёл их в компьютерную графику для хранения и интерполяции поворотов, и сейчас они используются везде, где нужно хранить поворот. Анимированный скелет хранит по одному кватерниону для каждого сустава в каждом ключевом кадре. Сетка может хранить касательный базис каждой вершины в виде кватерниона для карт нормалей. В сцене, построенной методом Gaussian splatting, каждая из миллионов гауссиан получает ориентацию, и это тоже кватернион. Такие программы сдерживают прежде всего память и пропускная способность, а не арифметика. Байт, сэкономленный на одном повороте, экономится миллионы раз.

Эти четыре числа не независимы. Как только известны три из них, четвёртое определено с точностью до знака. Поэтому компрессор хранит три числа и небольшой индекс, называемый картой, который указывает, как восстановить четвёртое число. Чаще всего используют метод трёх наименьших: отбрасывают компоненту, наибольшую по модулю, и записывают, какая это была компонента и её знак. Так работает ozz-animation, а также расширение glTF EXT_meshopt_compression и форматы сплатов SPZ и SOG.

В статье Compression of Uniformly Distributed Unit Quaternions, опубликованной на arXiv в октябре 2026 года, Карстен Фабер, Бастиан Кут, Ринальдо Шустер, Даниэль Паульс и Квирин Майер из Кобургского университета прикладных наук и искусств и компании AMD вместо этого делят на самую большую компоненту. Так поворот оказывается на поверхности четырёхмерного куба. Кубическая деформация a·x3 + (1 − a)·x с a = 0,373964 затем распределяет отсчёты равномернее, чем простой куб. Авторы называют полученный результат ℓ∞cub. Здесь это кодек на кубе. Четыре варианта выбора самой большой компоненты в сочетании с двумя знаками дают восемь карт, а восемь карт помещаются в три бита.

Биты, которые нельзя разделить на три

Поместим такой поворот в 32-битное слово. Карта занимает три бита и оставляет 29 бит на три числа, примерно по 9,67 бита на каждое. Битовые поля работают только с целыми битами. Каждое число занимает 9 бит, что даёт 512 уровней, при этом два бита слова остаются неиспользованными. Другой вариант: выделить одному числу 10 бит, а остальным меньше, чтобы одна ось поворота хранилась с большей точностью, чем другие.

В статье слово упаковывается в одно целое число в смешанной системе счисления, где у каждой цифры своё основание. Карта это цифра по основанию 8. Каждое из трёх чисел это цифра по основанию U. Упаковка трижды умножает на U и прибавляет. Распаковка трижды берёт остаток и делит, а то, что остаётся в конце, и есть карта. Наибольшее U, при котором 8·U3 всё ещё помещается в 232, равно 812. Каждая ось получает 812 уровней, а не 512, и шаг между соседними отсчётами сокращается примерно до 0,63 от шага битового поля. Бастиан Кут и Квирин Майер использовали ту же упаковку в 2021 году для весов смешивания вершин. Авторы сравнивают её с асимметричными системами счисления при равномерном распределении.

Во что обходится деление

Для декодера операция деления кажется медленной. Но здесь каждое основание постоянно, поэтому компилятор заменяет каждое деление и остаток умножением и сдвигом. Когда биты, оставшиеся после карты, делятся на три поровну, как при 24 и 48 битах с тремя битами карты, целочисленное деление совсем не требуется. Авторы измеряли время одного декодирования аппаратным счётчиком тактов на видеокарте AMD Radeon RX 7900 XTX. Их 32-битный декодер потребовал 111 тактов. Одна сферическая линейная интерполяция между двумя кватернионами заняла 171 такт на той же видеокарте. Метод MPEG-4, который деформирует куб тангенсом, потребовал 273 такта, поскольку тангенс компилируется в отношение синуса к косинусу. Кубическая деформация совмещается с шагом, который переводит уровень обратно в число, и вместе они стоят трёх совмещённых умножений-сложений (FMA).

Знак, который ничего не несёт

Кватернион и противоположный ему кватернион описывают один и тот же поворот. Кодек может менять знак каждого поворота так, чтобы самая большая компонента была положительной, и тогда знак вообще не нужно записывать. Некоторые библиотеки анимации так и делают. ozz-animation нет. На один ключ она тратит 48 бит: 15 бит на каждое из трёх чисел, два бита на карту и один бит на знак. Без знака остаётся 46 бит. Три одинаковых битовых поля не могут поделить 46 бит, поэтому библиотека сохраняет знак и по 15 бит на каждое число. В виде одного целого числа те же 46 бит дают по 41 285 уровней на каждую ось вместо 32 768, это целая часть от 246/3. Один возвращённый бит, поделённый на три оси, даёт каждой из них множитель 21/3, то есть около 1,26.

В качестве тестового набора использовался корпус Mixamo, все его 34 884 287 ключевых кадров. Исходный кодек ozz-animation давал максимальную погрешность 0,00909°. Кодек на кубе, сохраняя по 15 бит на каждое число и знак, снизил эту погрешность до 0,00203°. Отказ от знака снизил её до 0,00161°, в 5,6 раза меньше начального значения. 40-битный ключ без знака давал погрешность 0,01020°, на 12 процентов больше, чем у исходных 48 бит, но экономил по байту на каждом ключе, 33,3 МиБ на весь корпус. Рендеры дракона, анимированного обоими способами, показали сопоставимую ошибку изображения. Сэмплирование 1024 персонажей со скиннингом шло на 12–16 процентов быстрее, чем с исходным кодеком.

Касательный базис это поворот, который может быть ещё и отражённым, поскольку текстурные координаты могут быть зеркально перевёрнуты по шву. Бит, который больше не нужен для знака, может хранить ориентацию базиса. QTangents из CryEngine, представленные в 2011 году, хранили четыре 16-битные компоненты и прятали ориентацию в знаке четвёртой компоненты, отодвигая её от нуля, чтобы знак пережил округление. У кодека на кубе с 16 битами на базис восемь карт оставляют 13 бит на три числа. Битовые поля дали бы каждому числу по 16 уровней. Одно целое число даёт 20 уровней и использует 64 000 из 65 536 возможных кодов. В статье это указано как 15,97 использованного бита.

Уровней на ось: битовые поля и одно целое число
Что хранитсяБитыКартыБитовые поляОдно целое число
Поворот со знаком328512812
Ключ анимации без знака48432 76841 285
Ключ анимации без знака4044 0966 501
Касательный базис с ориентацией1681620

Гауссовы сплаты обрабатываются так же, поскольку кватернион и противоположный ему дают одну и ту же гауссиану. Рендерер Рейсдейка и его коллег упаковывает геометрию каждой гауссианы в 128 бит, из которых 30 отводятся на поворот, а сам поворот сжимается экспоненциальным отображением. На трёх сценах из набора Mip-NeRF 360 экспоненциальное отображение при 30 битах дало пиковое отношение сигнал/шум 45,90 дБ. Кодек на кубе достиг 45,83 дБ при 24 битах. При 16 битах он был впереди на 6,67 дБ. Декодирование поворотов занимало примерно 0,5 мс на кадр в обоих случаях, тогда как сам рендеринг требовал 11,8 мс.

Нечётное число уровней и нижняя граница

Битовое поле всегда содержит число уровней, равное степени двойки, то есть чётное. Квантователь из статьи размещает свои отсчёты в центрах равных шагов в диапазоне от −1 до 1, поэтому при чётном числе отсчётов ни один из них не попадает в ноль. В нуле, в центре своей карты, находится тождественный поворот, а в анимациях таких поворотов много. Из битового поля он никогда не восстанавливается точно. При нечётном числе один отсчёт оказывается в нуле, а упаковка в одно целое число позволяет кодеку выбрать нечётное число уровней. Авторы называют это тривиальным. Их анализ ошибок этот случай не охватывает.

У всего этого есть нижняя граница. В статье показано, что ни один код с 2k состояниями не может держать максимальную ошибку ниже примерно 96°, умноженных на 2−k/3. При большом бюджете битов кодеку на кубе нужно примерно на 1,5 бита больше этой границы. Граница предполагает, что повороты равномерно распределены по всем ориентациям. Анимационная дорожка, где поворот невелик, может обойтись меньшим, если подогнать диапазон под неё, и именно так делает библиотека Animation Compression Library. Все коды здесь одной длины, в отличие от этапа Хаффмана в сжатии JPEG, поэтому шейдер может прочитать любой поворот, не декодируя предыдущие.

Источник

Карстен Фабер, Бастиан Кут, Ринальдо Шустер, Даниэль Паульс и Квирин Майер, Compression of Uniformly Distributed Unit Quaternions, arXiv, октябрь 2026 года, DOI 10.48550/arXiv.2610.22052, опубликовано под лицензией CC BY 4.0. Все числа, замеры времени и границы в этой заметке взяты из этой статьи.

Раньше: Трассировка лучей