US2S1L17——透视投影变换
透视投影变换
-
获取透视投影的摄像机重要参数
-
透视投影变换到裁剪空间的矩阵
- 近裁剪面上的所有点保持不变
- 远裁剪面的z值不变,远裁剪面的中心点不变
- 远裁剪面宽高映射成近裁剪面的宽高
得到了最终的变换矩阵:
Aspect⋅tan(2FOV)10000tan(2FOV)10000−Far−NearFar+Near−100−Far−Near2Far⋅Near0
注意,由该矩阵转换出来的四维齐次坐标(x′,y′,z′,w′),其 w′ 很有可能不是1,
这时我们可以对坐标除以 w′ 标量,使其为1,这样得到的 wx′,wy′,wz′,如果在 (−1,1) 内就是不需要裁剪的
或者我们可以直接判断 x′,y′,z′ 是否在 (−w′,w′) 内,如果是就不需要裁剪
明确透视投影变换目标
我们这节课的目标就是要得到 将摄像机视锥体的 透视投影 转换到 齐次坐标系 时的 变换矩阵
我们可以将其分成三步来完成:
- 将透视视锥体变成一个长方体,将该长方体进行正交投影变换的操作(远裁剪面向z轴压缩,xy缩小而z不变)
- 将视锥体中心位移到观察空间原点中心
- 将长方体视锥体的x,y,z坐标范围映射到(-1,1)长宽高为2的正方体中
Unity中透视投影重要参数
Camera详细参数可见:U1L10-1——Camera可编辑参数相关,透视投影相关具体参数:Projection,Clipping Planes
-
Projection - 摄像机投影模式
-
Clipping Planes - 裁剪平面距离
- Near:近裁剪面离摄像机的距离
- Far:远裁剪面离摄像机的距离
根据已知参数,获取到远近裁剪面的高度:
-
已知:
- Near:近裁剪面离摄像机的距离
- Far:远裁剪面离摄像机的距离
- Field of view - FOV,决定视锥开口角度
-
可得:
- 近裁剪面高=2×Near×tan(2FOV)
- 远裁剪面高=2×Far×tan(2FOV)
现在我们已经可以得到远近裁剪面高,我们还需要知道远近裁剪面的宽,以便之后进行变换矩阵的推导
可以通过摄像机参数Camera.aspect得到Game窗口的宽高比
Aspect = 宽 : 高 = 宽 / 高
因此可得远近裁剪面宽:
- 近裁剪面宽=Aspect×近裁剪面高=Aspect×2×Near×tan(2FOV)
- 远裁剪面宽=Aspect×远裁剪面高=Aspect×2×Far×tan(2FOV)
于是,现在我们就可以得到在观察空间下,视锥体各个点的坐标:
透视投影变换矩阵的推导
-
将透视视锥体变成一个长方体,将该长方体进行正交投影变换的操作
想要实现右图的变换,我们需要满足3个特性:
- 近裁剪面上的所有点保持不变
- 远裁剪面的z值不变,远裁剪面的中心点不变
- 远裁剪面宽高映射成近裁剪面的宽高
我们只需要根据这3个特性得到对应的矩阵变换关系,然后进行推导即可
假设将透视视锥体变换为长方体视锥体的矩阵为 M变化矩阵
-
近裁剪面上的所有点保持不变
近裁剪面上的点 (x,y,Near,1) 变换后还是 (x,y,Near,1)
M变化矩阵xy−Near1=xy−Near1(注意,这里的Near是基于观察空间的,故为负数)
其中,x 和 y 等于0时,相当于就是近裁剪面的中心点,也满足下面的等式:
M变化矩阵00−Near1=00−Near1
-
远裁剪面的z值不变,远裁剪面的中心点不变
相当于 z 轴与远裁剪面的交点 (0,0,Far,1) 变换后仍为 (0,0,Far,1)
M变化矩阵00−Far1=00−Far1(注意,这里的Far是基于观察空间的,故为负数)
-
远裁剪面宽高映射成近裁剪面的宽高
这一步相对来说复杂一些,我们需要利用之前学习的知识点来进行一些推导:
-
透视投影视锥体内**顶点和原点连接,在近裁剪面的交点为投影点**
-
相似三角形的对应边成比例(k 称为相似比)
a′a=b′b=c′c=k
根据上面的知识,结合下图,可以推导出:
假设一个视锥体内的点坐标为 (X,Y,Z),经过透视视锥体变换为长方体视锥体以后坐标变为 (X′,Y′,Z):
-
x 轴变换情况:
XX′=Z−Near⇒X′=X⋅Z−Near
-
y 轴变换情况:
YY′=Z−Near⇒Y′=Y⋅Z−Near
-
已知 z 轴不变
通过此推导可得,视锥体内的所有点的x,y坐标都经过了同样的缩放,缩放因子为:Z−near
因此可以推导:
M变化矩阵xyz1=xZ−NearyZ−Near未知1
通过三小步的推导,我们得到三个与 M变化矩阵 相关的等式:
⎩⎨⎧M变化矩阵00−Near1=00−Near1 M变化矩阵00−Far1=00−Far1 M变化矩阵xyz1=xZ−NearyZ−Near未知1
根据上面三个等式,推导 M变化矩阵,步骤如下:
补充知识点: 四维齐次坐标乘以非零标量后,它映射的三维空间中的点不变 。我们通过该知识点对等式进行变形
-
先从信息最多的第三个等式来进行推导
首先对最终的结果进行一次变形
∵xZ−NearyZ−Near未知1×−z=x⋅Neary⋅Near未知−z(映射的点不变) ∴M变化矩阵xyz1=x⋅Neary⋅Near未知−z
根据上式得到的结果,对 M变化矩阵 进行反向推导,可以认为 M变化矩阵 可能的形式如下:
M变化矩阵=Near0000Near0000?−100?0(其中,将第三行前两个位置为0,是因为z的值和x,y无关)
将上面推导出来的矩阵乘以 xyz1 ,结果还是x⋅Neary⋅Near未知−z,说明 M变化矩阵 符合这种形式
现在,只需要推导出该变换矩阵的第三行的构成,就能够得到我们的目标: 将透视视锥体变成一个长方体的变换矩阵
故假设两个未知量分别为 a,b,得到:
M变化矩阵=Near0000Near0000a−100b0
-
接着,将上步推导的 M变化矩阵 代入到 1,2 式中:
先将 M变化矩阵 代入到1式内:
M变化矩阵00−Near1=Near0000Near0000a−100b000−Near1=00−Near1
对上式的结果进行变形:
∵00−Near1×Near=00−Near2Near(映射的点不变) ∴Near0000Near0000a−100b000−Near1=00−Near2Near
根据上式即可得到等式:
−a⋅Near+b=−Near2
在将 M变化矩阵 代入到2式内:
M变化矩阵00−Far1=Near0000Near0000a−100b000−Far1=00−Far1
对上式做相同的变形:
∵00−Far1×Far=00−Far2Far(映射的点不变) ∴Near0000Near0000a−100b000−Far1=00−Far2Far
根据上式即可得到等式:
−a⋅Far+b=−Far2
-
对得到的两个二元一次方程求解,得到 a,b:
{−a⋅Near+b=−Near2−a⋅Far+b=−Far2
由于 Far 和 Near 已知,故解方程 a,b 可得:
{a=Far+Nearb=Far×Near
最终,我们推导得到了 M变化矩阵 为:
M变化矩阵=Near0000Near0000Far+Near−100Far⋅Near0
-
将视锥体中心位移到观察空间原点中心
由于已将透视视锥体转换为了正方体视锥体,可以直接使用正交投影变换得出的结论:将视锥体中心位移到观察空间原点中心
平移矩阵为:
100001000010002Near+Far1
-
将长方体视锥体的x,y,z坐标范围映射到(-1,1)长宽高为2的正方体中
由于已将透视视锥体转换为了正方体视锥体,因此可以使用正交投影变换的推导过程:
将长方体视锥体的x,y,z坐标范围映射到(-1,1)长宽高为2的正方体中
但需要注意的是,透视投影的观察空间中的x,y,z和齐次坐标系中x,y,z的关系与正交投影不一致,
这是因为远近裁剪面的宽高的计算方法和正交投影不一致,
透视投影的观察空间中的x,y,z和齐次坐标系中x,y,z的关系如下图:
根据这个关系图,可以得到一些转换公式:
⎩⎨⎧X齐=2×Aspect×Near×tan(2FOV)2X观Y齐=2×Near×tan(2FOV)2Y观Z未取反=−Near−(−Far)2Z观=Far−Near2Z观
同样,由于要将右手坐标系(观察空间)转换为左手坐标系(裁剪空间),因此要对z分量取反,最终得到公式:
⎩⎨⎧X齐=Aspect×Near×tan(2FOV)1X观Y齐=Near×tan(2FOV)1Y观Z齐=−Far−Near2Z观
将其转换为矩阵:
Aspect×Near×tan(2FOV)10000Near×tan(2FOV)10000−Far−Near200001
以上三步得到了三个矩阵,将其合并为一个矩阵,得到最终的 透视投影空间 转换到 齐次坐标裁剪空间 的变换矩阵
Aspect×Near×tan(2FOV)10000Near×tan(2FOV)10000−Far−Near200001100001000010002Near+Far1Near0000Near0000Far+Near−100Far⋅Near0=Aspect⋅tan(2FOV)10000tan(2FOV)10000−Far−NearFar+Near−100−Far−Near2Far⋅Near0
注意,由该矩阵转换出来的四维齐次坐标**(x′,y′,z′,w′)** ,其 w′ 很有可能不是1,
这时我们可以对坐标除以 w′ 标量,使其为1,这样得到的 wx′,wy′,wz′ ,如果在 (−1,1) 内就是不需要裁剪的
或者我们可以直接判断 x′,y′,z′ 是否在 (−w′,w′) 内,如果是就不需要裁剪