3D图形处理 - 如何计算模型视图矩阵

sli*_*mbo 9 hardware opengl math 3d graphics

我无法理解从对象空间转换到视图空间的数学.我在硬件中这样做,我有下面的Atranspose矩阵:

ATranspose =

         [rightx      upx     lookx    0]
         [righty      upy     looky    0]
         [rightz      upz     lookz    0]
         [-eyeright -eyeup -eyelook    1]
Run Code Online (Sandbox Code Playgroud)

然后找到我们要做的观点:

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

  xnew = xold*rightx + xold*righty + xold*rightz + xold*(-eyeright)
Run Code Online (Sandbox Code Playgroud)

但我不确定这是否正确.

它也可能是

   [x,y,z,1]=atranspose*[x',y',z',1]T
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释一下吗?我无法在网上找到任何不直接与opengl代码相关的内容,我只是想了解从对象坐标到眼睛坐标转换点背后的数学.

JCo*_*per 13

这个答案可能比它需要的时间长得多.如果您已经理解了大部分矩阵数学,那么请跳至最后2段左右.

从一维问题开始可能最简单.在1D中,我们在一条线上有点.我们可以扩展它们或者我们可以翻译它们.考虑三个点I,J,K和变换矩阵中号.

M = [ s t ]
    [ 0 1 ]

i = [1]   j = [-2]   k = [0]
    [1]       [ 1]       [1]

 j     k  i
???????????????
-2 -1  0  1  2
Run Code Online (Sandbox Code Playgroud)

当我们乘以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  ]
Run Code Online (Sandbox Code Playgroud)

因此,如果我们为st赋值,那么我们就可以在我们的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
Run Code Online (Sandbox Code Playgroud)

重要的是要注意转换的顺序是至关重要的.这些1D变换缩放然后翻译.如果你要先翻译,那么'点'将与原点的距离不同,因此缩放因子会对它产生不同的影响.出于这个原因,转换通常保存在单独的矩阵中,以便顺序清晰.

如果我们向上移动到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 ]
Run Code Online (Sandbox Code Playgroud)

该矩阵将1)由缩放点SX,SY,2)旋转围绕原点通过一个度,然后3平移由点TX,TY.注意,该矩阵是在假设点被表示为列向量并且乘法将作为Np发生的情况下构造的.正如datenwolf所说,如果你想使用点的行向量表示但应用相同的转换,你可以转置所有内容并交换顺序.这是矩阵乘法的一般性质:(AB)^ T =(B ^ T)(A ^ T).

也就是说,我们可以谈论对象,世界和眼睛坐标方面的变换.如果眼睛坐在世界的原点,向下俯视世界的负z轴,向右+向上+ +向上+对象,一个立方体,坐下10个单位-z(以z为中心)轴),沿世界x的宽度为2,沿z的宽度为3,沿世界y的高度为4.然后,如果立方体的中心是对象的本地参照系,并且其局部轴方便地与世界轴对齐.然后,对象坐标中框的顶点是变体[+/-1,+/-2,+/-1.5]^T.近,上,右(从眼睛的视点)顶点有对象坐标 [1,2,1.5]^T,在世界坐标中,相同的顶点是[1,2,-8.5]^T(1.5-10 = -8.5).由于映入眼帘的是,它指向的方式,而我们定义我们的眼睛一样的OpenGL的事实,该顶点具有相同的眼坐标世界坐标.因此,让我们继续前进并转动眼球,使得眼球的X正确的(RT)和眼睛的Ÿ向上和眼睛的-z看(LK)和眼睛定位在[eyeright(ex) eyeup(ey) eyelook(ez)]^T.由于我们希望将对象坐标转换为眼睛坐标(意味着我们将眼睛视为原点),我们将采用这些转换的反转并将它们应用于对象顶点(在它们被转换为世界坐标之后).所以我们将:

ep = [WORLD_TO_EYE]*[OBJECT_TO_WORLD]*wp;
Run Code Online (Sandbox Code Playgroud)

更具体地说,对于我们感兴趣的顶点,我们将:

[ 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 ]
Run Code Online (Sandbox Code Playgroud)

为方便起见,我已经将眼睛的旋转影响了它.实际上,既然我已经写了这么多,这可能是混乱的一点.您提供的矩阵将旋转然后翻译.我假设眼睛的翻译是在世界坐标中.但正如你在问题中写的那样,它实际上是在眼睛坐标中进行翻译.我也否定了lk因为我们已经将眼睛定义为俯视负z轴,但是为了制作标准旋转矩阵,我们想要使用正值.

无论如何,我可以坚持下去,但也许这已经回答了你的问题.


继续:

进一步解释上述内容,将眼睛的变换分成两个部分也使得更容易找到逆.很容易看出,如果平移tx将眼睛移动到相对于世界物体的某个地方,我们可以通过-tx移动世界上的所有东西并保持眼睛静止,从而在眼睛和世界各点之间保持相同的相对位置.

同样,考虑眼睛的方向由其默认的,向上外观向量定义:

     [1]      [0]      [ 0]
d_rt=[0] d_up=[1] d_lk=[ 0]
     [0]      [0]      [-1]
Run Code Online (Sandbox Code Playgroud)

创建一个将这三个向量指向新方向的旋转矩阵很容易.我们只是排列我们的三个新轴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]
Run Code Online (Sandbox Code Playgroud)

很容易看出,如果你增加d_rt,d_up和d_lk并乘以上面的矩阵,你会分别得到rt,uplk.所以我们应用了我们想要的转型.要成为正确的旋转,三个向量必须是正交的.这实际上只是基础的变化.由于这个事实,我们可以通过其转置非常方便地找到该矩阵的逆.这就是我上面所做的.如果将该转置矩阵应用于世界坐标中的所有点并使眼睛保持静止,则这些点将相对于眼睛保持相同的位置,就像眼睛旋转一样.


例如:

分配(以世界坐标):

   [ 0]    [0]    [-1]     [-2]     [1.5]
rt=[ 0] up=[1] lk=[ 0] eye=[ 0] obj=[ 0 ]
   [-1]    [0]    [ 0]     [ 1]     [-3 ]
Run Code Online (Sandbox Code Playgroud)

简单的相机/网格示例