Обработка 3D-графики - Как рассчитать матрицу вида модели - PullRequest
9 голосов
/ 27 апреля 2011

У меня проблемы с пониманием математики для преобразования из пространства объектов в пространство просмотра. Я делаю это аппаратно, и у меня есть матрица Atranspose ниже:

ATranspose =

         [rightx      upx     lookx    0]
         [righty      upy     looky    0]
         [rightz      upz     lookz    0]
         [-eyeright -eyeup -eyelook    1]

Затем, чтобы найти точку, мы сделаем:

  [x,y,z,1] = [x',y',z',1]*ATranspose

  xnew = xold*rightx + xold*righty + xold*rightz + xold*(-eyeright)

но я не уверен, правильно ли это.

Это также может быть

   [x,y,z,1]=atranspose*[x',y',z',1]T

Может кто-нибудь, пожалуйста, объясните мне это? Я не могу найти в Интернете ничего такого, что не связано напрямую с кодом opengl. Я просто хочу понять математику преобразования точек из координат объекта в координаты глаза.

Ответы [ 2 ]

13 голосов
/ 27 апреля 2011

Этот ответ, вероятно, намного длиннее, чем нужно.Перейдите к нижним 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

1 голос
/ 27 апреля 2011

Если вы транспонируете ATranspose во втором варианте, т.е.

[x,y,z,w]^T = ATranspose^T * [x',y',z',w']^T

Кстати, ^T означает транспонирование, поэтому, вероятно, первоначальный автор имел в виду

[x,y,z,w] = [x',y',z',w'] * A^T

и переписано

[x,y,z,w]^T = A^T * [x',y',z',w']^T

тогда все эти формулировки одинаково верны.

...