10分钟入门opengl投影变换推导(内含mathjax公式)
perspective projection
title: perspective projection tags: ["openGL", "Markdown", "mathjax"] notebook: notes
关于投影变换
NDC
我们先介绍一个概念,NDC(Normalized Device Coordinates).我们在opengl右手坐标系里建立的模型都会映射到NDC.所以所有的点坐标的分量都会在[-1,1]间,超出的将被clip掉.尔后,NDC将坐标映射到viewport(视口),那为什么会有NDC这个中间产物?计算方便。不管是在后面映射视口,还是矩阵计算.特别要注意的是NDC
是左手坐标系
左为perspective projection,这跟我们看到的真实世界是一样的原理.有很强的3D视感.而右边.则是ortho projection,如果你学过工程制图.想必也很熟悉.没有近大远小的概念 下面,我们试着计算投影公式.这里我们用一下缩写
{l=leftr=rightf=farn=nearb=bottomt=top
将下图的立方体空间映射到NDC空间.假设下面空间中一点(x,y,z,w),求(xndc,yndc,zndc,wndc)
r−l2=x−lxndc+1=>xndc=2r−lx+l+rl−r
yndc,zndc同理,很容易得到矩阵 [2r−l00l+rl−r02t−b0b+tb−t002f−nn+fn−f0001]
frustum 1
同样,根据等比公式,得到如下公式,我们假设还一组中间变量(xp,yp,zp,wp),代表(x,y,z,w)映射到near面上的点.(注意,这里还没有转换到NDC) {zx=−nxpzy=−nypzp=n=>{xp=−nxzyp=−nyzzp=n 到这,我们已经做完了投影影射
90%的工作,接下来我们需要将投影点再映射到NDC
以xp为例 {al+b=−1ar+b=1=>{a=2r−lb=l+rl−r 也就是说 xp 在NDC
里的映射是用这个线性函数
xndc=2r−lxp+l+rl−r=2r−l−nxz+l+rl−r 我们发现个问题..这写不进矩阵.但又发现,左右乘以z,有一些新发现
zxndc=−2nr−lx+l+rl−rz
是不是有点感觉了
[−2nr−l0l+rl−r0000000000000][x001]=[xndc∗z000]
同理,得到yp
[−2nr−l0l+rl−r00−2bt−bb+tb−t000000000][xy01]=[xndc∗zyndc∗z00]
到这个地方我得停住说点别的. 上面公式中,我们求到的点都是放大了当前点的z倍. 所以必须除以z.而除z这个操作,学名叫 perspective divide
,这个操作不用你操心,opengl 管线中会自动处理.自动除z??不对啊.我们在投影变换完后znpc轴都在一个平面了.还原不出原始的z了啊! 人类的智慧是无穷的.我们可以将z复制到在w分量上,所以管线中的perspective divide
操作其实就是除以w.而w=z.这样我们就得到矩阵第4行的值.要还原投影点,perspective divide
将(xp,yp,zp)分别除以z(z=w).得到的点为(xp/z,yp/z,zp/z,z), 请特别注意它们的下标!!要除的z是最原始点的z. 我们尝试构造第三行.
A,B,C,D
[−2nr−l0l+rl−r00−2bt−bb+tb−t0ABCD0010][xyz1]=[xndczyndczzz]
$$
Ax+By+Cz+D=zndc∗z 我们知道这个方程组,有两个解(要注意z值是在动态变化的)
{Ax+By+Cn+D=−1nAx+By+Cf+D=1f 不妨令A=B=0,使其与x,y无关,解以下方程组 {Cn+D=−n Cf+D=f=>{C=f+nf−nD=2fnf−n 到此,我们求得投影变化矩阵为
[−2nr−l0l+rl−r00−2bt−bb+tb−t000f+nf−n2fnf−n0010]
frustum 2
frustum 1 介绍的方法,需要6参数.而且不太直观.下面介绍另一种常见的构造投影变换的方法. 不管用什么方法,只要参数能够确定唯一的一个frustum.就行. 我们先看一张网上淘来的图..
fov=field of view.视野,我们假定它为相机上平面与下平面的夹角θ.
near,跟 far 就很显然了. 我们还需要一个参数.那就是近平面的宽高比值记作ar(aspect ratio).
好了.参数有了. θ,ar,n,f, 下面求矩阵 因为zndc的投影变换只与n,f有关,上面frustum 1中已经有公式.不再赘述. 比如先求yndc,我们垂直从+x看到-x.很容易得到如下公式 ypn=yz=>yp=yz˙n 再将y映射到yndc: yndc−(−1)2=yp−btanθ˙n 而其中 b=−tanθ2˙n 解方程得到: yndc˙z=ytanθ2 同理得到 xndc˙z=xar˙tanθ2 后面的计算frustum 1里已经说过.组合一下上面的结果为:
[1ar˙tanθ200001tanθ20000f+nf−n2fnn−f0010]
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· 分享一个我遇到过的“量子力学”级别的BUG。
· Linux系列:如何调试 malloc 的底层源码
· 对象命名为何需要避免'-er'和'-or'后缀
· JDK 24 发布,新特性解读!
· C# 中比较实用的关键字,基础高频面试题!
· .NET 10 Preview 2 增强了 Blazor 和.NET MAUI
· SQL Server如何跟踪自动统计信息更新?