透视矩阵详解

在一开始我接触到透视矩阵的时候,很困惑,包括我在看games101的时候,透视矩阵的推理,并不能完全说服我,就是硬凑我的,让我从根本上理解这个透视矩阵到底在做什么,在自我学习的过程中,我翻阅了很多资料包括

OpenGL Projection Matrix (songho.ca)中对透视变换的论述,以及在games中的方法论述,我会发现这两者推出来的最终式子不同(最后搞清楚是约定的问题),就整的自己有点迷惑(可能是我脑子不太好使吧~~)现在开始,我会努力把这个矩阵,以及我为什么要搞出这个式子讲清楚。

约定(这很重要,会让你的推理变得更清晰):

这里我们做出约定,文中的所有变量例如n, f , z都是表示具体坐标,而不是传入的数值;

nf是我们传入的近远平面的与视点的距离,是个正值;

opengl中的nf平面映射方式:n -> -1, f -> 1, games101中 n -> 1, f -> -1,这里我希望用opengl中的映射方式;

opengl和games101中mv变换都是处于右手坐标系下的,但是因为opengl中将nf映射的方式会导致坐标系旋向变换,变成左手系;

透视投影:

当我们将场景中的点变换到view坐标系下之后,相机位于原点,看向-z方向,所以有如下图:

透视矩阵详解_第1张图片

可以看到,从原点看去,空间中任意点都将都投影在投影平面(近平面)投影为(x', y', z'),这里做投影的话z'其实已经没有意义了,因为我只需要知道你在我屏幕上应该处于哪个点,所以就有:

所以大功告成?引用ssloy的一句话:

If you simply copy-paste this formula without understanding the above material, I hate you.

但是我们希望能够将这个公式转化为一个矩阵

因为矩阵在坐标变换中有良好的性质,所有变换都用上述式子得形式转化我们的坐标的话,对于需要做很多变换的情形下时,对所有点我们都不得不做很多次计算,基本是每次变换都要进行一次运算,但是矩阵连乘(从右读到左的变换顺序+矩阵有结合律)能够表示一系列的变换,并且可以一次性求出所有变换为一个矩阵,这样就可以用一个矩阵表示一系列变换,极大减小运算量。
但这里需要除以一个轴上的坐标,我们就不得不引入齐次坐标方式来计算,让计算到的w = z,然后用除法实现变换,这个除法就叫做透视除法。

并且我希望他能够保留z方向的深度值,因为我单单拿这个式子来计算,我会丢失深度,如果这个方向上有多个点,我就不知道最终应该画谁了,所以我们希望这个变换能将nf变换到[-1, 1]范围中,保留z的信息,用来作为深度测试的参考,并且在TAA等时间域上的处理时要用屏幕坐标信息去计算motion vector

注意games101的推论本质上也是跟这个一样,只不过闫老师是将nf映射到了nf本身这个范围内,基本思想也是映射-保留z的信息。我们这里直接映射到了[-1, 1]范围,后续就只需要做xy方向上的移动缩放了。

那么现在我们的目标很明确,需要求一个矩阵Mp使得能够实现这样一个变换:

这里我并不知道z会被变换到哪里去,那就先不管,看别的行:

很容易得出013:

其实从这里我们就能看到了,齐次矩阵的第四行第三列代表着w的值,该位置1也就意味着w=z,使得xy拥有了透视投影的性质。

然后是第三行,我们能够知道的是n被映射到-1, f被映射到了1;

那么就有

我们知道z的值不依赖于xy,所以A & B = 0

那么就有:

于是有

再将xy方向上的投影平面变换到【-1, 1】范围:

透视矩阵详解_第2张图片

左乘Mp得到最终透视变换矩阵

透视矩阵详解_第3张图片

我们得到了最终的透视矩阵

注意我们这里和opengl的矩阵有点不太一样,但其实是一样的,只不过我们的nfz都是实际坐标值。

但其实我们的透视行为还未真正开始,这一步我们得到的空间叫做裁剪空间,在齐次坐标系下我们的裁剪能够有很好的性质,不过这是另外一件事了。

从这里我们能看出来,做了投影变换之后的坐标,对于一个点,w = z,也就是其深度坐标,对于opengl用-z的,其实也一样,所以说讲的严密点,是其在view空间下的深度的负数。

你可能感兴趣的:(实时渲染,图形学,矩阵,线性代数,numpy,图形渲染)