MVP矩阵转换
MVP矩阵转换
矩阵与空间
有哪些矩阵?有哪些坐标空间?
矩阵:模型矩阵(Model)、观察矩阵(View)、投影矩阵(Projection)。
空间:局部空间(Local Space)、世界空间(World Space)、观察空间(View Space)、裁剪空间(Clip Space)、屏幕空间(Screen Space)。
MVP矩阵指的就是就是这三个矩阵,而我们的能获取的顶点坐标起始则在局部空间(也称模型空间)。
-局部空间以模型原点为中心,我们通过M模型矩阵把局部空间的顶点转换到以世界原点为中心的世界空间下
-接着通过V观察矩阵将世界空间下的顶点转换到以摄像机为中心的观察空间中
-再通过P矩阵把观察空间下的顶点转换到可见范围内的裁剪空间,P矩阵不是真正的投影,目的是帮助判断顶点是否可见,只是为投影做准备。
模型矩阵
局部空间-世界空间
虽然是对点做变换,但是三维图形本质就是又一堆三维顶点围成的,因此对所有三维顶点做变换就等价于对三维图形本身做了同等变换。而这意味着每个模型都有自己独立的局部空间。
注意区分左右手坐标系,比如DirectX使用左手坐标系,OpenGL则使用右手坐标系
M矩阵各变换矩阵(缩放-旋转-*移变换矩阵)如下:
在计算M矩阵时,由于矩阵计算是不满足交换律的,所以务必按照缩放-旋转-*移的顺序来进行矩阵变换。否则若先进行*移之类的操作,则会把*移的距离也进行缩放和旋转从而得到不正确的结果。
观察矩阵
世界空间-观察空间
世界空间更多用来描述绝对位置。
观察矩阵是吧所有顶点从世界坐标系变换到以相机视角下的坐标系,为此我们需要知道相机的位置点P和相机的朝向Dir。
我们默认这个前向朝向就是z轴的朝向,那么:
x轴向量R为向量(0,1,0)与Dir叉乘的结果。
y轴向量U为向量Dir与向量R叉乘的结果。
这样我们就能得出观察矩阵的结果为——
但是该矩阵计算方法有个问题,如果两两*行的向量叉乘就会得到一个无效向量从而使得结果错误。为了解决这个问题我们可以限制角度的范围,也可以用四元数和旋转变换矩阵规避。
因为观察矩阵本质是*移和旋转操作,由于相机的变换是在世界空间中先旋转再*移后得到的,所以我们先计算*移,再进行旋转,即仍然按照之前的变换矩阵的操作方法进行坐标系变换即可规避这个问题。使用*移变换矩阵和旋转变换矩阵的结果为——
在Unity中,世界空间坐标中默认为左手坐标系,而观察空间是右手坐标系,因此这里第一个矩阵对z轴进行了一个反向计算。
投影矩阵
观察空间-裁剪空间
投影矩阵不是真正的投影,目的是帮助判断顶点是否可见,只是为投影做准备。它把顶点坐标都变换到[-1,1](NDC坐标系)之间。
观察空间用于决定顶点的剔除与保留,在unity中,只有观察空间是右手坐标系,这关系到z轴的取反。
根据变换方式的不同,通常分为正交投影矩阵和透视投影矩阵。
如下图,左边是透视投影,右边是正交投影:
正交投影
正交投影它如何把坐标变换到[-1,1]呢,一般的做法是把一定范围内的顶点进行线性缩放。
那么如图所示中,对于每个点P(xp,yp,zp)都被映射到了点N(xn,yn,zn):
-x方向上,把[-r,r]映射到了[-1,1],如果不是中心对称则会映射到[l,r],该部分可记作:
-y方向上,把[-t,t]映射到了[-1,1],如果不是中心对称则会映射到[b,t],该部分可记作:
-z方向上,把[n,f]均匀映射到了[-1,1],该部分怎么理解呢。我们z的长度为far-near,而我们实际的映射空间为[-1,1],即实际映射的空间长度为2,因此我们的z轴要等距缩放-2/(far-near),同时把z轴的中心点位移到[-1,1]的中心,缩放后这段位移的大小为-(far+near)/(far-near),该部分可记作:
即矩阵P到N的变换以变换矩阵来表达的话,就是:
当然同理,我们也能用进行缩放变换矩阵和位移变换矩阵的形式来表达,这样会使得这个过程更加直观,如下图则是先进行了一次均匀变换到[-1,1]的缩放变换,然后再把自身的位置挪到原点的位移变换,最后的变换矩阵形式:
考虑到坐标系的不同,会存在其他参考的结果与这里完全相反的情况,实际上是因为坐标系的不同而造成的,两者都是对的。
透视投影
透视投影则相对于正交投影更复杂一些。
透视投影为了模拟这样一种*大远小的效果,将视锥体中的顶点都投影到*裁剪*面上,我们需要根据这种投影关系来对顶点进行变换,我们仍然默认相机距离*裁剪*面的距离为near,而到远裁剪*面的距离为far。
如上图所示,如果我们要把点P(x,y,z)映射为Q(x',y',near) ,就可以利用相似三角形的性质来进行推导,即:
然后我们需要把*裁剪*面上的点x'和y‘再映射到[-1,1],这里可以参考上面正交投影的计算方法。但是我们实际上使用的是canonical cube(我们把它叫做正则、规范、标准立方体)的长和宽,为此我们引入纵横比Aspect,和FOV(Field of View 垂直方向张开的角度)。
那么我们就能从左图计算得知这个视锥体截面的宽为near·tan(FOV/2),那么也就能得知长为Aspect·near·tan(FOV/2)。然后同理我们就能将其代入正交矩阵的公式得到:
这里其实我去翻了一下其他的资料,发现这里大家用了另一种方式来表达,也就是用余切来表示的:
因为1/tanΘ就等于cotΘ,这里的Θ角度就是FOV/2,本质上是一样的,仅仅是表达形式上的不同。
接下来我们处理z方向的映射,为了*处的物体能有很大的深度精度,这里的z并不是像正交透视矩阵那样变换,但是我们能确定是从[-near,-f]映射到[-1,1],即可进行方程组的联立从而得出z轴的变换
最后让这些值都消去z分母分量,整理为透视变换矩阵,如果要把矩阵-1改成1的话,对应也要把位移量改成正的:
参考
GAMES101-现代计算机图形学入门-闫令琪-Lecture 04 Transformation Cont.
【技术美术百人计划】图形 1.2.3 MVP矩阵运算
跳转回百人合集