关于透视投影的深入理解

  • 转载请注明出处
一些术语
  • fov即视野,是视锥体在xz平面或者yz平面的开角角度,具体哪个平面都可以。OpenGLD3D都使用yz平面。
  • aspect即投影平面的宽高比。
  • far是远裁剪平面的距离。

左边是在xz平面计算视锥体,右边是在yz平面计算视锥体:

在这里插入图片描述
OrMmiGRsYZpoUIj.jpg

在这里插入图片描述

在这里插入图片描述

xz平面计算视锥体, top = right / aspect使用了除法, 在yz平面计算视锥体, right = top x aspect, 这也许就是为什么图形APIs采用yz平面的原因


齐次坐标可除性

对于一个普通坐标的点P=(Px, Py, Pz),有对应的一族齐次坐标 ( w P x , w P y , w P z , w ) (wPx, wPy, wPz, w) (wPx,wPy,wPz,w),其中 w w w 不等于零。比如, P ( 1 , 4 , 7 ) P(1, 4, 7) P(1,4,7) 的齐次坐标有 ( 1 , 4 , 7 , 1 ) 、 ( 2 , 8 , 14 , 2 ) 、 ( − 0.1 , − 0.4 , − 0.7 , − 0.1 ) (1, 4, 7, 1)、(2, 8, 14, 2)、(-0.1, -0.4, -0.7, -0.1) (1,4,7,1)2,8,14,2(0.1,0.4,0.7,0.1) 等等。因此,如果把一个点从普通坐标变成齐次坐标,给 x , y , z x,y,z x,y,z 乘上同一个非零数 w w w,然后增加第4个分量 w w w;如果把一个齐次坐标转换成普通坐标,把前三个坐标同时除以第4个坐标,然后去掉第4个分量

简单的线性插值

基本思想是:给一个x属于*[a, b],找到y属于[c, d],使得xa的距离比上ab长度所得到的比例,等于yc的距离比上cd*长度所得到的比例,用数学表达式描述很容易理解:

在这里插入图片描述

此外,如果x不在[a, b]内,比如 x < a x < a x<a 或者 x > b x > b x>b,则得到的y也是符合y < c或者y > d,比例仍然不变,插值同样适用。

透视投影变换

透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum) 变换到 规则观察体(Canonical View Volume)

在这里插入图片描述

  • 透视投影变换由两步组成:
1. 用透视变换矩阵把顶点从视锥体中变换到裁剪空间的CVV中。
2. CVV裁剪完成后进行透视除法

在这里插入图片描述

上图是右手坐标系中顶点在相机空间中的情形。设 P(x,z) 是经过相机变换之后的点(是处于相机坐标系中),视锥体由eye——眼睛位置,np——近裁剪平面,fp——远裁剪平面组成。N是眼睛到近裁剪平面的距离F是眼睛到远裁剪平面的距离投影面可以选择任何平行于近裁剪平面的平面,这里我们选择近裁剪平面作为投影平面。设 P’(x’,z’) 是投影之后的点,则有 z’ = -N。通过相似三角形性质,我们有关系:

在这里插入图片描述

在这里插入图片描述

这样,我们便得到了P投影后的点P’

在这里插入图片描述

从上面可以看出,投影的结果 z ’ z’ z 始终等于 − N -N N,在投影面上。实际上, z ’ z’ z 对于投影后的 P ’ P’ P 已经没有意义了,这个信息点已经没用了。但对于3D图形管线来说,为了便于进行后面的片元操作,例如z缓冲消隐算法,有必要把投影之前的 z z z 保存下来,方便后面使用。因此,我们利用这个没用的信息点存储 z z z,处理成:

在这里插入图片描述

  • 上面的操作是只用普通投影变换, 下面结合CVV进行思考,假入能够把上面写成这个形式

在这里插入图片描述

  • 这里我可以理解成是在透视投影的前提下向CVV靠拢, 通过这个变换, 想把 z 限制在 -1~1 之间, 下面就可以非常方便的用矩阵以及齐次坐标理论来表达投影变换:

在这里插入图片描述

其中 P’代表的是 P 映射到单位立方体后的投影点

在这里插入图片描述

( N x , N y , a z + b , − z ) T (N_x, N_y, az+b, -z)^T (Nx,Ny,az+b,z)T 变为 ( − N x / z , − N y / z , − ( a z + b ) / z , 1 ) T (-N_x/z, -N_y/z, -(az+b)/z, 1)^T (Nx/z,Ny/z,(az+b)/z,1)T 这一步是使用齐次坐标变普通坐标的规则完成的, 在透视投影过程中称为透视除法Perspective Division), 经过这一步,就丢弃了原始的z值(得到了CVV中对应的z值)

但是为什么要把z写成 − a z + b z -\frac{az+b}{z} zaz+b , 因为:

  1. 后面投影之后的光栅化阶段,要通过x’和y’对z进行线性插值,以求出三角形内部片元的z,进行z缓冲深度测试。在数学上,投影后的x’和y’,与z不是线性关系,与1/z才是线性关系。 − a z + b z -\frac{az+b}{z} zaz+b 正是 1 / z 1/z 1/z 的线性关系。即 -a+b/z
  2. 后面的CVV是一个x,y,z的范围都为 [-1,1] 的规则体,便于进行多边形裁剪。而我们可以适当的选择系数ab, 使得 − a z + b z -\frac{az+b}{z} zaz+b 这个式子在z = -N的时候值为 -1,而在z = -F的时候值为 1,从而在z方向上构建CVV
  • 接下来我们就求出ab

在这里插入图片描述

这样我们就得到了透视投影矩阵的初始限制z得到的投影矩阵:

在这里插入图片描述

但是xy方向仍然没有限制在 [-1,1] 中, 为了能在xy方向把顶点从Frustum 情形 变成CVV情形,我们开始对 xy 进行处理, 现在得到的是:

在这里插入图片描述

我们知道 -Nx / z 的有效范围是投影平面的左右边界值 [left, right], -Ny / z[bottom, top] , 现在使用线性插值把 -Nx / z 属于 [left, right] 映射到 x 属于 [-1, 1] 中,-Ny / z 属于 [bottom, top] 映射到 y 属于 [-1, 1]

  • 线性插值就是说 x 属于 [a, b],找到y属于 [c, d],使得xa的距离比上 ab 长度所得到的比例

在这里插入图片描述

上图中 ,左边的x代表的是相机坐标系中的x, 右边是立方体投影下的 x, 对 y 同理。 所谓立方体的投影就是说 在保证透视投影关系的情况下,再变换到立方体范围内, 后续再用正交投影啥的,所以开头的透视投影只是个约束

  • 经过线性插值, 我们得到了最终的投影点:

在这里插入图片描述

这里的 P’ 只变化了 xy 分量的形式,az+b-z 是不变的,则我们做透视除法的逆处理–> 给 P’每个分量乘上-z,得到:

在这里插入图片描述

而这个结果又是这么来的:

在这里插入图片描述

  • 也就是我们通过一个透视变换矩阵M从 视锥体相机坐标系的点 变到了透视投影约束立方体 内的点 , 改写下M, 得到:

在这里插入图片描述

  • 变换矩阵也就是这样:
    在这里插入图片描述
重要的简化

上述矩阵时一般的视见体矩阵,如果视见体是对称的,即满足r=−l,t=−b,则矩阵P可以简化为:
在这里插入图片描述

注意到M的最后一行不是***(0 0 0 1)而是 (0 0 -1 0),因此可以看出透视变换不是一种仿射变换,它是非线性的, 但是现在存在的问题是 CVV的宽高是相同的,即宽高比永远是1。容易造成多边形的失真现象, 比如一个投影面上的正方形在CVV的面上可能变成了一个长方形, 解决这个问题的方法就是在对多变形进行透视变换、裁剪、透视除法之后,在归一化的设备坐标(Normalized Device Coordinates)上进行的视口(viewport)变换中进行校正,它会把归一化的顶点之间按照和投影面上相同的比例变换到视口中,从而解除透视投影变换带来的失真现象*。进行校正前提就是要使投影平面的宽高比和视口的宽高比相同

程序处理与理论的不同

假如是理论推导的话, 应该从世界坐标系出发, 通过 R,t 变换到相机坐标系, 然后到图像物理坐标系再到图像像素坐标系, 但是这个并不是程序中使用的方法, 它没有变换到正方体再视口变换这一步, 推荐 B站讲透视投影的一个up的视频

  • 下面是一般程序中使用的透视变换的完整流程图
    在这里插入图片描述
参考链接

透视投影
视口变换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

live_for_myself

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值