
上图是3D渲染过程中的空间变换过程,这里主要讨论观察空间到裁剪空间的转换。
由上图可知,经过观察变换后,空间变换为观察空间,也就是以摄像机坐标为原点的空间,这是接下来推导的前提。
下图是一个视锥体,在视锥体范围内的物体为可视的,不在视锥体内的为不可视。

我们有两个任务:
1、判断一个点是否在视锥体内(用于裁剪超出屏幕的点)。
2、计算顶点在裁剪空间上的坐标。
我们先忘掉矩阵的概念,只用基本的三维几何知识完成第一点。
先假定一个场景如下图:
已知以下参数:
fov:视锥体上下两个截面的夹角,此参数由设定摄像机参数时给定了
n:近截面z轴坐标,此参数由设定摄像机参数时给定了
f:远截面z轴坐标,此参数由设定摄像机参数时给定了
aspect:屏幕宽高比,此参数由设定摄像机参数时给定了
H:平行于远截面,并且经过P点的平面的高的一半,可通过计算得出
由此,我们只需要判断P点的y轴坐标除以H是否大于1(当y为负时是否小于-1),即可知道P点是否在y轴方向上超出了视椎体。同理可求出x轴。
下面先求y方向。
H=z∗tan(fov/2)
y/H=y/z∗tan(fov/2)
接下来求x方向,假设经过此P点截面的宽度为W
W=aspect∗H
W=aspect∗z∗tan(fov/2)
x/W=x/(aspect∗z∗tan(fov/2))
最后求z方向
(z−n)/(f−n)
我们已经获得计算点是否在视锥体内的计算方式,现在我们把它转换为矩阵的形式,设M为我们要求的转换矩阵,可得:
M⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡z∗tan(fov/2)xaspect∗z∗tan(fov/2)y(z−n)/(f−n)1⎦⎥⎥⎤
⎣⎢⎢⎡m00m10m20m30m01m11m21m31m02m12m22m32m03m13m23m33⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡z∗tan(fov/2)xaspect∗z∗tan(fov/2)y(z−n)/(f−n)1⎦⎥⎥⎤
我们发现求解m00∗x+m01∗y+m02∗z+m03=z∗aspect∗tan(fov/2)1很难找出合适的m00和m02,因为左边x和z是以加法的形式相邻,右边z确成为了x的分母。
解决方法:将右边的齐次坐标每一项乘以z,所以有:
⎣⎢⎢⎡m00m10m20m30m01m11m21m31m02m12m22m32m03m13m23m33⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡tan(fov/2)xaspect∗tan(fov/2)yz∗(z−n)/(f−n)z⎦⎥⎥⎤
所以可以求得矩阵为:
⎣⎢⎢⎡tan(fov/2)10000aspect∗tan(fov/2)10000m22100m230⎦⎥⎥⎤
m22∗z+m23=z∗(z−n)/(f−n)
我们知道,当z=n时,(z−n)/(f−n)=−1 所以 m22∗n+m23=−n
当z=f时,当z=n时,(z−n)/(f−n)=1 所以 m22∗f+m23=f
联立{m22∗n+m23=−nm22∗f+m23=f
求得{m22=n−f−f−nm23=n−f2∗f∗n
最后求得投影矩阵为:
⎣⎢⎢⎢⎡tan(fov/2)10000aspect∗tan(fov/2)10000n−f−f−n100n−f2∗f∗n0⎦⎥⎥⎥⎤
注意,通过此矩阵转换后的坐标是齐次坐标,只要除以w分量,根据结果就可以判断是否在[-1,1]范围内,也就是该点是否在视椎体内。
透视投影矩阵只是为了获得一个齐次坐标,为投影做准备,实际不进行真正的投影,真正的屏幕投影是在下一个阶段执行的。
相较于https://www.cnblogs.com/bluebean/p/5276111.html,本文是用另外一种几何思路推导透视投影矩阵,可以互相参考。