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

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

推导的思路

正交投影和透视投影的做用都是把用户坐标映射到OpenGL的可视区域。若是咱们能根据两者的变换矩阵来推出最终通过映射的坐标范围刚好是OpenGL的可视区域,也就是反向推导出了这两个投影矩阵。函数

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

正交投影

变换效果

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

矩阵定义

下图是正交投影矩阵。cdn

-w400
https://cdn.wxdut.com/ 参数解释以下:

-w400

只考虑x轴和y轴,则:blog

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

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

经过上面那个矩阵,就能够转换成[-1,+1]范围内的对应的坐标。下面对此进行证实。it

数学推导

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

则,矩阵*向量class

\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]的区间。

-w400

矩阵定义

-w400

参数解释以下:

-w400

透视矩阵有些特殊,并未说明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坐标变换中起到了很是重要的做用。在二维图像显示时通常使用正交变换,在三维图像显示时就要用到透视变换。理解这两个变换对应的矩阵的做用对咱们理解这两个变换很重要。

相关文章
相关标签/搜索