Этот ответ, вероятно, намного длиннее, чем нужно.Перейдите к нижним 2 абзацам или около того, если вы уже понимаете большую часть математической математики.
Начать проще всего с рассмотрения одномерной задачи.В 1D у нас есть точки на линии.Мы можем масштабировать их или мы можем перевести их.Рассмотрим три точки i, j, k и матрицу преобразования M .
M = [ s t ]
[ 0 1 ]
i = [1] j = [-2] k = [0]
[1] [ 1] [1]
j k i
─┴──┴──┴──┴──┴─
-2 -1 0 1 2
Когда мы умножим на M , получим:
i' = Mi = [ s t ][ 1] = [ s+t ]
[ 0 1 ][ 1] [ 1 ]
j' = Mj = [ s t ][-2] = [-2s+t]
[ 0 1 ][ 1] [ 1 ]
k' = Mk = [ s t ][ 0] = [ t ]
[ 0 1 ][ 1] [ 1 ]
Таким образом, если мы присваиваем значения s и t , то мы получаем различные преобразования в нашем 1D "треугольнике".Масштабирование изменяет расстояние между «точками», в то время как чистый перевод перемещает их относительно начала координат, сохраняя постоянный интервал:
s=1 t=0 s=2 t=1 s=1 t=2
j k i j k i j k i
─┴──┴──┴──┴──┴─ ─┴──┴──┴──┴──┴─ ─┴──┴──┴──┴──┴─
-2 -1 0 1 2 -3 -1 1 3 5 0 1 2 3 4
Важно отметить, что порядок преобразований является критическим.Эти одномерные преобразования масштабируются и затем переводятся.Если бы вы сначала перевели, то «точка» была бы на другом расстоянии от начала координат, поэтому коэффициент масштабирования влиял бы на него по-другому.По этой причине преобразования часто хранятся в отдельных матрицах, так что порядок ясен.
Если мы перейдем к 2D, мы получим матрицу N :
[1 0 tx][ cos(a) sin(a) 0][sx 0 0] [ sx*cos(a) sx*sin(a) tx ]
N =[0 1 ty][-sin(a) cos(a) 0][ 0 sy 0]=[-sy*sin(a) sy*cos(a) ty ]
[0 0 1 ][ 0 0 1][ 0 0 1] [ 0 0 1 ]
Эта матрица будет 1) масштабировать точку на sx, sy , 2) поверните точку вокруг начала координат на a градусов, а затем 3 переведите точку на tx,ти .Обратите внимание, что эта матрица построена в предположении, что точки представлены в виде векторов столбцов и что умножение будет иметь вид Np .Как сказал datenwolf, если вы хотите использовать векторное представление точек, но применять то же преобразование, вы можете транспонировать все и менять порядок.Это общее свойство умножения матриц: (AB) ^ T = (B ^ T) (A ^ T) .
Тем не менее, мы можем говорить о преобразованиях в терминах объекта, мира и координат глаза.Если глаз сидит у источника мира, смотрит вниз на отрицательную ось z мира, с + x вправо и + y вверх, а объект, куб, сидит на 10 единиц вниз -z (с центром в zось), с шириной 2 вдоль мира x, глубиной 3 вдоль оси z и высотой 4 вдоль мира y.Затем, если центр куба является локальной системой отсчета объекта и его локальные оси удобно совмещены с мировыми осями.Тогда вершины ящика в координатах объекта являются вариациями [+/-1,+/-2,+/-1.5]^T
.Ближняя, верхняя, правая (с точки зрения глаза) вершина имеет координаты объекта [1,2,1.5]^T
, в мировые координаты , та же самая вершина равна [1,2,-8.5]^T
(1,5-10 = -8,5).Из-за того, где находится глаз, куда он направлен, и того факта, что мы определяем наш глаз так же, как OpenGL, эта вершина имеет те же координаты глаза , что и мировые координаты .Итак, давайте переместим и повернем глаз так, чтобы x было вправо (rt) , а y равнялось up и глазу -z - это взгляд (lk) , а глаз расположен на [eyeright(ex) eyeup(ey) eyelook(ez)]^T
.Поскольку мы хотим, чтобы координаты объекта были преобразованы в координаты глаза (это означает, что мы будем рассматривать глаз как источник), мы возьмем обратное к этим преобразованиям и применим их к вершинам объекта (после того, как они были преобразованы в мировые координаты).Таким образом, у нас будет:
ep = [WORLD_TO_EYE]*[OBJECT_TO_WORLD]*wp;
Более конкретно, для нашей интересующей вершины у нас будет:
[ rt.x rt.y rt.z 0][1 0 0 -ex][1 0 0 0 ][ 1 ]
[ up.x up.y up.z 0][0 1 0 -ey][0 1 0 0 ][ 2 ]
[-lk.x -lk.y -lk.z 0][0 0 1 -ez][0 0 1 -10][1.5]
[ 0 0 0 1][0 0 0 1 ][0 0 0 1 ][ 1 ]
Для удобства я выделил перевод, на который влияет вращение глаза.На самом деле, теперь, когда я написал так много, это может привести к путанице.Матрица, которую вы дали, будет вращаться, а затем переводить.Я предположил, что перевод глаза был в мировых координатах.Но, как вы написали в своем вопросе, он фактически выполняет перевод в координатах глаза.Я также отрицал lk , потому что мы определили, что глаз должен смотреть вниз по отрицательной оси z, но чтобы создать стандартную матрицу вращения, мы хотим использовать положительные значения.
В любом случае, я могу продолжать, но, возможно, это уже отвечает на ваш вопрос.
Продолжение:
Объяснение вышесказанного немного дальше, отделяя превращение глаза вдва компонента также значительно облегчают поиск обратного.Легко видеть, что если перевод tx перемещает глаз куда-то относительно объектов в мире, мы можем поддерживать одинаковые относительные положения между глазом и точками в мире, перемещая все в мире с помощью -tx и удержание глаза в неподвижном состоянии.
Точно так же учитывайте ориентацию глаза, определенную по умолчанию вправо , вверх и посмотрите векторов:
[1] [0] [ 0]
d_rt=[0] d_up=[1] d_lk=[ 0]
[0] [0] [-1]
Создать матрицу вращения, которая направит эти три вектора в новом направлении, легко.Мы просто выстраиваем наши три новые оси rt , up , lk (как векторы столбцов):
[rt.x up.x -lk.x 0]
[rt.y up.y -lk.y 0]
[rt.z up.z -lk.z 0]
[ 0 0 0 1]
Это легко увидетьчто если вы увеличиваете d_rt, d_up и d_lk и умножаете на вышеуказанную матрицу, вы получаете rt , up и lk обратно соответственно.Итак, мы применили преобразование, которое мы хотели.Для правильного вращения три вектора должны быть ортонормированными.Это действительно просто смена баз.Из-за этого мы можем довольно легко найти обратную матрицу, взяв ее транспонирование.Это то, что я сделал выше.Если вы примените эту транспонированную матрицу ко всем точкам в мировых координатах и оставите глаз неподвижным, точки будут сохранять то же положение относительно глаза, как если бы глаз вращался.
ДляПример:
Назначить (в мировых координатах):
[ 0] [0] [-1] [-2] [1.5]
rt=[ 0] up=[1] lk=[ 0] eye=[ 0] obj=[ 0 ]
[-1] [0] [ 0] [ 1] [-3 ]
![Simple camera/grid example](https://i.stack.imgur.com/m7c5o.png)