OpenGL中投影变换矩阵的反向推导

在OpenGL中有两个重要的投影变换:正交投影(Orthographic Projection)和透视投影(Perspective Projection),二者各有对应的变换矩阵。初学者比较难理解这两个矩阵是怎么来的。本文从数学角度来反向推导两个投影矩阵。

推导的思路

正交投影和透视投影的作用都是把用户坐标映射到OpenGL的可视区域。如果我们能根据二者的变换矩阵来推出最终经过映射的坐标范围恰好是OpenGL的可视区域,也就是反向推导出了这两个投影矩阵。

OpenGL的可视区域的坐标范围是一个边长为2的立方体。每个维度上的大小是2,范围是[-1,+1]。经过各种变换之后的坐标超出[-1,+1]范围的部分将不会显示到屏幕上。

正交投影

变换效果

正交投影在OpenGL中的作用是调整屏幕宽高比,并将实际定义的坐标转换成[-1,+1]范围内的对应的坐标。

矩阵定义

下图是正交投影矩阵。

https://cdn.wxdut.com/ 参数解释如下:

只考虑x轴和y轴,则:

在定义物体的坐标的时候,坐标范围为:

\begin{cases} x \in [left, right]& \text{}\\ y \in [top, bottom]& \text{} \end{cases}

通过上面那个矩阵,就可以转换成[-1,+1]范围内的对应的坐标。下面对此进行证明。

数学推导

① 假设物体上的一个坐标为(x,y,z,1),其中,x的范围为[left, right],y的范围为[top, bottom],z的范围为[near, far]

则,矩阵*向量

\left[ \begin{array}{cccc} \frac{2}{right-left} & 0 & 0 & -\frac{right+left}{right-left}\\ 0 & \frac{2}{top-bottom} & 0 & -\frac{top+bottom}{top-bottom}\\ 0 & 0 & \frac{-2}{far-near} & -\frac{far+near}{far-near}\\ 0 & 0 & 0 & 1 \end{array}  \right]× \left[ \begin{array}{c} x\\ y\\ z\\ 1 \end{array}  \right]= \left[ \begin{array}{c} \frac{2x-left-right}{right-left}\\ \frac{2y-top-bottom}{bottom-top}\\ \frac{2z-near-far}{far-near}\\ 1 \end{array}  \right ]

即,

x1=\frac{2x-left-right}{right-left}
y1=\frac{2y-top-bottom}{bottom-top}
z1=\frac{2z-near-far}{far-near}
w1=1

② 考虑到perspective divide的存在,此时w=1,所以:

x1=\frac{2x-left-right}{(right-left)w1}=\frac{2x-left-right}{right-left}
y1=\frac{2y-top-bottom}{(bottom-top)w1}=\frac{2y-top-bottom}{bottom-top}
z1=\frac{2z-near-far}{(far-near)w1}=\frac{2z-near-far}{far-near}

② 先证明x轴确实落在了[-1, +1]的范围。

很明显,x1是关于x的一元一次线性函数。

x1=f(x)=\frac{2*x-left-right}{right-left}

所以x=right的时候,f(x)最大,x=left的时候,f(x)最小。

代入方程,得到:

f(x)=\begin{cases} f(x) = -1,& \text{x=left}\\ f(x) = 1,& \text{x=right} \end{cases}

③ 所以

x1=f(x)\in [-1, +1]

同理,y1和z1的范围也是[-1, +1]。

证明结束。

小结

正交变换是将物体的坐标转换成OpenGL的坐标。

变换前的范围为:

\begin{cases} x \in [left, right],& \text{}\\ y \in [bottom, top],& \text{}\\ z \in [near, far],& \text{} \end{cases}

变换后的范围为:

\begin{cases} x \in [-1, 1],& \text{}\\ y \in [-1, 1],& \text{}\\ z \in [-1, 1],& \text{} \end{cases}

透视投影

变换效果

在用2D屏幕展现3D场景时,会有一种近大远小的感觉。OpenGL也是利用这一原理实现在2D屏幕上的3D效果。透视投影会形成一个视椎体,在视椎体内的坐标都是可以绘制到屏幕上的,也就是说,在视椎体上的坐标范围都会被调整到[-1, +1]的区间。

矩阵定义

参数解释如下:

透视矩阵有些特殊,并未说明x和y的范围,下面通过推导得出这个范围。

数学推导

① 假设物体上的一个坐标为(x,y,z,1)

则,矩阵*向量的结果为:

\left[ \begin{array}{cccc} \frac{a}{aspect} & 0 & 0 & 0\\ 0 & a & 0 & 0\\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2fn}{f-n}\\ 0 & 0 & -1 & 0 \end{array}  \right]× \left[ \begin{array}{c} x\\ y\\ z\\ 1 \end{array}  \right]= \left[ \begin{array}{c} \frac{ax}{aspect}\\ ay\\ -\frac{f+n+2fnw}{f-n}\\ -z \end{array}  \right ]

即,

x1=\frac{ax}{aspect}
y1=ay
z1=-\frac{(f+n)z+2fnw}{f-n}
w1=-z

② 考虑perspective divide的存在,得到:

x2=\frac{x1}{w1}=\frac{-ax}{aspect * z}
y2=\frac{y1}{w1}=-\frac{ay}{z}
z2=\frac{z1}{w1}=\frac{(f+n)z+2fn}{(f-n)z}

③ 求:当结果落在了[-1, +1]的范围的时候,x的范围是多少?

很明显,x2是关于x的一元一次线性函数。

x2=f(x)=\frac{-ax}{aspect*z}

下面推算当x2的范围为[-1, +1]的时候,x的范围

x=\begin{cases} \frac{aspect*z}{a},& \text{f(x)=-1}\\ -\frac{aspect*z}{a},& \text{f(x)=1} \end{cases}

所以,x的范围为

[\frac{aspect*z}{a},-\frac{aspect*z}{a}]

这里注意,按照习惯,z一般都是负数,所以上面的区间范围是没问题的,下同。

④ 求:当结果落在了[-1, +1]的范围的时候,y的范围是多少?

因为,

y2=f(y)=-\frac{ay}{z}

分别求y1为1和-1时,y的值。

y=\begin{cases} \frac{z}{a},& \text{f(y)=-1}\\ -\frac{z}{a},& \text{f(y)=1} \end{cases}

所以,y的范围为

[\frac{z}{a},-\frac{z}{a}]

⑤ 求:当结果落在了[-1, +1]的范围的时候,z的范围是多少?

因为,

z2=f(z)=\frac{z1}{w1}=\frac{(f+n)z+2fn}{(f-n)z}

-1<=f(z)<=1

则有,

-1<=\frac{(f+n)z+2fn}{(f-n)z}<=1

解方程得,

-1<=f(z)<=1

所以,

n<=z<=f

即变换前的坐标一定要在平截椎体的Z轴范围内才能最终展示到屏幕上。

证明结束。

小结

透视变换是将物体的坐标转换成OpenGL的坐标。

变换前的范围为:

\begin{cases} x \in [\frac{aspect*z}{a},-\frac{aspect*z}{a}],& \text{}\\ y \in [\frac{z}{a},-\frac{z}{a}],& \text{}\\ z \in [n,f],& \text{} \end{cases}

变换后的范围为:

\begin{cases} x \in [-1, 1],& \text{}\\ y \in [-1, 1],& \text{}\\ z \in [-1, 1],& \text{} \end{cases}

附上透视椎体的图解:

总结

矩阵变换在OpenGL坐标变换中起到了非常重要的作用。在二维图像显示时一般使用正交变换,在三维图像显示时就要用到透视变换。理解这两个变换对应的矩阵的作用对我们理解这两个变换很重要。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值