如何推导出两个空间之间的变换矩阵呢?
已知条件:
- 空间A在空间B中的坐标轴矢量为
- x轴 Xa(Xax, Xay, Xaz)
- y轴 Ya(Xay, Yay, Zay)
- z轴 Za(Xaz, Yay, Zaz)
- 空间A的原点在空间B中的坐标为
Oa(Oax, Oay, Oaz)
已知规则:
点p(x,y,z)的几何意义在于,从原点开始,先后按照X,Y,Z轴三个方向分别平移x,y,z个单位,得到的点即为p。
空间A到空间B的变换矩阵
由以上可知,已知空间B中的一点
Pb(a,b,c)
则其在空间A中的坐标为:
Pa = Oa + a * Xa + b * Ya + c * Za
将以上表达式,转换为按列展开的矩阵表达式:
现在就得到了将空间A中的点转换到空间B中的变换矩阵
因为平移变换对矢量无效,所以将以上矩阵的最后一行,最后一列去除,即为矢量对应的变换矩阵
这就是为什么会看到Shader中解取了变换矩阵的前3行3列来对法线,光照方向进行空间变换了。
最后需要注意的是,实际应用中的三个轴矢量有可能是经过缩放变换了,所以不能保证是规一化的。
小结
- 由以上推导可以看出,空间A到空间B的变换矩阵,只需要将空间A在空间B中的轴矢量,原点坐标分别按列展开构造矩阵即可。
空间B到空间A的变换矩阵
因为已知了空间A到空间B的变换矩阵Mab,则只需要求其逆矩阵即可。
如果空间A的三个轴向量是规一化的,即没有经过缩放变换的,则矩阵Mab是正交的,所以其转置矩阵就是其逆矩阵。由此得到空间B到空间A的变换矩阵:
通过变换矩阵可以得到,空间B在空间A中的三个轴矢量分别为矩阵Mba的前三列。又因为是转置矩阵,所以还是矩阵Mab的前三行。
加上平移之后的仿射变换矩阵为
观察空间
Unity中相机空间中,正前方指向-z轴方向。所以在用到
Camera.cameraToWorldMatrix
,Camera.worldToCamraMatrix
等接口时需要多注意。-
视矩阵推导
- 一方面可以根据上述轴方向的方法构造矩阵
- 另一方面,世界中的点相对于相机的坐标即为其相机空间坐标,则只需要计算出将相机还原到世界原点的变换即可,然后对世界中的点施以此变换即为此点相对于相机的坐标了。
已知相机在世界中的坐标p(10,0,0)与旋转r(30,0,0),其意义为将世界原点渲染r,然后再按p平移。
-
那么相机世界中的原点到世界原点的变换为上一步操作的逆操作,先反向平移p,再反向旋转r。最后由于相机空间使用右手坐标系,正向为-z方向,再将z取反即可。
现在使用p,r分别构造平移矩阵与旋转矩阵即可
其它
- 观察空间与投影空间不同,屏幕空间是一个二维空间,从观察空间到屏幕空间的变换操作,叫投影
裁剪空间
顶点从相机空间转换到裁剪空间(也称齐次裁剪空间),这个用于变换的矩阵称为裁剪矩阵,也称为投影矩阵。
裁剪空间由视锥体决定。投影分为透视投影,正交投影。其中透视投影有近大远小的效果,模拟了人眼的视觉效果。
投影矩阵的意义:
- 由于存在两种投影,如果直接使用视锥体定义的空间来进行裁剪,则不同的投影就需要不同的处理过程,同时对于透视视锥体来说,判断一个点是否处于其内容比较困难。因些需要使用一种更加通用,方便的方式来进行裁剪工作
投影矩阵的目的:
投影预处理
虽然投影矩阵中有『投影』二字,但并没有真正的进行投影,而是在做投影前的预处理。真正的投影发生在齐次除法中。经过投影矩阵的变换后,顶点分量w不再为1,而是具体有特殊的值跟意义。坐标缩放
对x,y,z坐标分量进行缩放,w分量存储了这三个分量的范围值。如果这三个分量在这个范围内,则说明这个顶点在裁剪空间内,进而不会被剔除掉。
投影矩阵的推导
http://blog.csdn.net/popy007/article/details/1797121
又因为,tan(fov/2) = (h/2) / N,将N = h / ( 2tan(fov/2) )代入矩阵M,得到由Fov与Aspect表示的投影变换矩阵:
变换后的点为
可以看出,投影矩阵的本质就是对x,y,z进行缩放,对z还有平移,以便于裁剪。此时顶点的w分量已经不是1了。这时只需要判断x,y,z三个分量是否在w值的范围内即可
-w <= x' <= w
-w <= y' <= w
-w <= z' <= w
正交投影矩阵
变换矩阵为
变换后的点为
使用正交投影矩阵变换为,顶点的w分量仍然为1。本质是因为投影矩阵最后一行不同。透视投影矩阵的最后一行是[0 0 -1 0],而正交投影矩阵的最后一行是[0 0 0 1]。判断一个变换后的顶点是不是位于视锥体内使用的不等式与投影矩阵一样,这种通用性也是为什么要使用投影矩阵的原因之一。
屏幕空间
经过投影矩阵变换后的顶点,经过裁剪操作,就可以经过真正的投影操作了,将视锥体投影到屏幕空间中。经过这一步变换,得到最终的屏幕像素坐标。
主要有以下两个步骤:
-
齐次除法,也称为透视除法。
将x,y,z三个分量分别除以w分量即可。得到的坐标叫做归一化设备坐标(Normalized Device Coordinates, NDC)。
Unity使用OpenGL规范,NDC坐标x,y,z的范围都为[-1,1],而DirectX平台中,z在[0,1]范围内。
-
屏幕像素坐标计算
Unity中屏幕空间左下角为原点,与OpenGL相同,而DirectX平台中左上角为原点。
将归一化后的NDC坐标代入公式,得到顶点对应的屏幕像素坐标。