Как я могу вращаться вокруг произвольной точки в 3D (вместо начала координат)?

15

У меня есть некоторые модели, которые я хочу вращать, используя кватернионы обычным способом, за исключением того, что вместо поворота вокруг источника я хочу, чтобы он был слегка смещен. Я знаю, что в трехмерном пространстве вы не говорите, что вращаетесь вокруг точки; Вы говорите, что вращаетесь вокруг оси. Так что я визуализирую это как вращение вокруг вектора, хвост которого расположен не у локального источника.

Все аффинные преобразования в моем механизме рендеринга / физики хранятся с использованием SQT (масштаб, кватернион, перевод; идея заимствована из книги « Архитектура игрового движка» ). Поэтому я строю матрицу каждого кадра из этих компонентов и передаю ее вершинному шейдеру. В этой системе применяется перевод, затем масштабирование, затем вращение.

В одном конкретном случае мне нужно перевести объект в мировое пространство, масштабировать его и повернуть вокруг вершины, не центрированной в локальном начале объекта.

Вопрос: Учитывая ограничения моей нынешней системы, описанные выше, как я могу добиться локального вращения с центром в точке, отличной от начала координат? Автоматическое upvote для тех, кто может описать, как это сделать, используя только матрицы :)

notlesh
источник
Кватернионы уже описывают вращение вокруг произвольной оси; у вас есть проблемы с построением такого кватерниона из ваших данных?
Мартин Сойка
3
Серьезно, могут ли люди, которые высказывают ответы, действительно их читать ? Я дал метод, эффективную формулу и даже демонстрацию. Тем не менее, единственный ответ с отрицательным результатом, хотя и предоставляет некоторую ценную информацию (а также некоторую явно неверную информацию), не содержит ни одного из них и даже не отвечает на вопрос!
Сэм Хоцевар
@MartinSojka, это примерно произвольная точка, а не произвольная ось.
Нотлеш
@ SamHocevar Оба ваших ответа были полезны. Я выбрал ваш, потому что он был более тщательным и помог мне прийти к решению. Спасибо вам обоим.
Notlesh
Ах, извините - я перепутал это с двойными кватернионами (они также переводят вас "бесплатно"). Я напишу, что я имел в виду в ответе позже; может быть, другие сочтут это полезным, тем более что вы можете сократить свои три компонента до одного, хотя и немного более сложного.
Мартин Сойка

Ответы:

17

Короче говоря

Вам нужно всего лишь изменить T в своей форме SQT.

Замените вектор перевода vна v' = v-invscale(p-invrotate(p))где vначальный вектор перевода, pэто точка, вокруг которой вы хотите, чтобы вращение происходило, invrotateи invscaleинверсии вашего вращения и масштаба.

Быстрая демонстрация

Позвольте pбыть точкой, вокруг которой вы применяете вращение r. Позвольте sбыть ваши параметры масштабирования и vваш вектор перевода. Окончательное преобразование матрицы T(p)R(r)T(-p)S(s)T(v)вместо R(r)S(s)T(v).

То, что вы хотите, это новые параметры преобразования v', r'и s'так, чтобы окончательное преобразование матрицы было, R(r')S(s')T(v')и мы имеем:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

Поведение на бесконечности указывает, что параметры вращения и параметры масштабирования не могут изменяться (это можно продемонстрировать). У нас при этом есть r = r'и s = s'. Поэтому единственный отсутствующий параметр - v'ваш новый вектор перевода:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Если эти матрицы равны, их обратные значения равны:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Это особенно верно для происхождения O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Масштабирование и вращение начала координат дает начало координат, таким образом получая:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'это новый вектор перевода, который вы ищете, который позволяет сохранить ваше преобразование в форме SQT. Возможно, возможно упростить вычисления; но по крайней мере необходимое хранилище не увеличивается.

Сэм Хоцевар
источник
Спасибо за объяснение. Кстати, вы знаете какие-нибудь ресурсы, где я мог бы прочитать больше о приемах представления SQT?
Пачанга
Поправьте меня, если я ошибаюсь, но похоже, что другим решением было бы сохранить ваш кватернион как обычно, и если вам нужно учесть перевод вокруг произвольной точки / оси, а затем построить матрицу Q с учетом этого, просто извлеките вектор перевода из этой матрицы (обычно в последнем столбце) и добавьте ее в вектор перевода объектов, затем выбросьте временную матрицу.
Джонбейкерс
15

Все канонические формулы вращения, используемые для получения ваших матриц вращения, предназначены для вращения вокруг начала координат. Если вы хотите вместо этого применить это вращение вокруг определенной точки, вы должны сначала сместить начало координат или, что то же самое, переместить объект так, чтобы точка, вокруг которой вы хотите повернуть, находилась в начале координат.

Сначала рассмотрим 2D-случай, потому что он проще, а метод масштабируется. Если бы у вас был куб шириной 2 с центром в начале координат, и вы хотели повернуть его на 45 градусов вокруг своего центра, это было бы тривиальным применением матрицы вращения 2D .

Но если вместо этого вы хотите повернуть его вокруг его верхнего правого угла (расположенного в 1,1), вам сначала нужно перевести его так, чтобы этот угол был в начале координат. Это может быть достигнуто с переводом -1,-1. Затем вы можете вращать объект, как и раньше, но вы должны следить за этим, переводя его обратно (мимо 1,1). Итак, в общем, для достижения матрицы поворота Rдля поворота rоколо точки Pвы делаете:

R = translate(-P) * rotate(r) * translate(P)

где translateи rotate- канонические матрицы перевода / вращения соответственно. Как это случается, это тривиально масштабируется до 3D, за исключением того, что необходимо также включить ось для вращения - вы всегда можете выбрать канонические матрицы вращения X, Y или Z, но это будет скучно. Вы хотите использовать произвольную матрицу вращения оси-угла . Ваш финал Rв 3D, таким образом:

R = translate(-P) * rotate(a,r) * translate(P)

где a- единичный вектор, представляющий ось вращения, и Pтеперь это трехмерная точка в пространстве модели, представляющая точку вращения.

Когда это происходит, кватернионы могут быть преобразованы в матричные представления и из них , так что вы можете выполнить конкатенацию таким образом, если захотите. Или вы можете просто оставить все в виде матриц (кватернионы имеют некоторые приятные преимущества, такие как простота интерполяции в разумной манере, но нужно ли вам это или нет).

Также:

Так что я визуализирую это как вращение вокруг вектора, хвост которого расположен не у локального источника.

Строго говоря, хотя векторы можно использовать для представления позиций, рассматривая их как смещения от начала координат, сами векторы не имеют самих позиций, поэтому немного необычно визуализировать их как таковые.


источник
Спасибо, это хороший ответ. Это не соответствует ограничениям моей системы. Я должен был включить в свой вопрос «возможно ли это сделать с учетом этих ограничений?», И я думаю, что ответ таков: это не так, поскольку для этого требуется два перевода, а я только один. Является ли это неизбежным недостатком использования SQT в качестве представления аффинных преобразований?
Нотлеш
Он идеально вписывается в ваши ограничения. Матрица R (создается как translate-rotate-translate-back) является вашей матрицей вращения. Замените Q на R в вашей системе "SQT", чтобы у вас была более распространенная парадигма масштабирования-поворота-перевода, и все готово. Этот последний перевод не зависит от двух промежуточных переводов, выполненных для получения желаемого вращения.
Вы предлагаете заменить кватернион на матрицу? Это еще 12 байтов на объект (8, если я сохраню это как матрицу 4x3)! Я заткну оптимиста во мне, и поверну. (На самом деле это, вероятно, даже не приведет к увеличению занимаемой площади на 2 КБ ...) Спасибо за ваши ответы.
Нотлеш
Вы могли бы - вы могли бы также конвертировать между ними, создавая кватернион вращения таким образом и подключаясь обратно к вашей существующей системе.
1
@SamHocevar: Альтернативно, любая их комбинация может быть выражена как один винт .
Мартин Сойка