透视投影矩阵(所有都是右乘列向量)
投影矩阵简单版(从某视频里看到的):
f为投影焦距。
以下是unity的透视投影矩阵:
解释一下各个变量,结合下图理解:
Fov:是unity摄像机上的一个属性,Field of View。表示摄像机的张开角度。
Far:unity摄像机上的一个属性。表示近裁剪切面和摄像机的距离。
Near:unity摄像机上的一个属性。表示远裁剪切面和摄像机的距离。
Ascept:Ascept = nearClipPlaneWidth / nearClipPlaneHeight
而 nearClipPlaneHeight = 2 * Near * tan(Fov / 2) 这是指近裁剪平面的高度。
nearClipPlaneWidth 可通过camera.aspect来算(w/h)。其实就是直接去camera.aspect这个属性。
以下是乘了一组向量以后的:
判断一个顶点是否在裁剪空间内,就判断x、y、z三个分量是否满足以下不等式,一个不满足就说明要被剔除。
-w <= x <= w
-w <= x <= w
-w <= x <= w
正交投影矩阵
解释,同样结合下图:
Near和Far和上面的透视投影一样,Size是摄像机上的一个属性,所以farClipPlaneHeight = 2 * Size;
aspect还是通过camera.aspect获取。
以下是和一组向量相乘后的结果:
判断是否裁剪,和透视投影矩阵一样。
屏幕空间
通过投影矩阵变换、裁剪操作,接下来就是投影到屏幕了。
经过透视投影变换后的裁剪控件,经过齐次除法后会变换到一个立方体内,就是用齐次坐标系的w分量去除以x、y、z分量(书上说的,我觉得应该是各个分量除以w,不然要是有一个分量是0的话不就炸了嘛。。。)。这样可以使齐次坐标标准化,即w = 1。
然后通过公式算出屏幕的x、y坐标:
ScreenX = (x * pixelWidth) / (2 * w) + pixelWidth / 2
ScreenY = (x * pixelHeight) / (2 * w) + pixelHeight/ 2
z分量会被用于深度缓冲。
法线变换
首先,法线是垂直于切线的,变换后的切线可以使用原来顶点变换的变换矩阵得到。
但是,对于法线来说,用原来的顶点变换矩阵可能会使原来的法线不一定垂直于切线(比如说非统一缩放)。
假设已知切线Ta、法线Na他们相互垂直,因此,Ta · Na = 0;已知变换矩阵Mab,变换后的法线Tb = MabTa,求一个矩阵G变换法线Na,使变换后的法线任然与Tb垂直。
Tb·Nb = (MabTa) ·(GNa) = 0
(MabTa) ·(GNa) = (MabTa)T(GNa) = TaTMabTGNa= TaT(MabTG)Na = 0
因为Ta · Na = 0,所以如果MabTG = I,那么上面等式成立。所以G = (MabT)-1 = (Mab-1)T,G就是顶点变换矩阵的转置的逆。
如果变换矩阵是正交矩阵,那么我们可以直接使用变换顶点的变换矩阵来得到变换后的法线。