前言
我在阅读《unityshader入门精要》时,发现书上并没有给出投影矩阵的推导过程
投影矩阵在图形学有很关键的作用,在游戏开发,虚拟现实和增强现实,机器人学,机器视觉都有涉及到
我想用最直观的方式,解释透视正交投影如何得到的
想要看懂本文,要对缩放旋转平移,3大矩阵要清晰透彻的认识
正交投影
我们先从简单的正交投影开始,想要学习透视矩阵的,建议先学会正交矩阵
Size:竖直方向上高度的一半,NearHeight/2
Aspect,摄像机横纵比,Aspect=
N
e
a
r
W
i
d
t
h
N
e
a
r
H
e
i
g
h
t
{\frac{NearWidth}{NearHeight}}
NearHeightNearWidth
根据已知的Size,Near,Far,Apect求出变换矩阵
先将长方体进行缩放,让xyz都在[-1,1],
如下图所示,
对于y轴,对于点2.y=
N
e
a
r
H
e
i
g
h
t
2
\frac{NearHeight}{2}
2NearHeight=Size,Size=>1,k2=
1
S
i
z
e
\frac{1}{Size}
Size1
直观的理解就是y轴从Size=>1,y轴缩放大小是
1
S
i
z
e
\frac{1}{Size}
Size1
Aspect(简称a)=
N
e
a
r
W
i
d
t
h
N
e
a
r
H
e
i
g
h
t
{\frac{NearWidth}{NearHeight}}
NearHeightNearWidth,w=ah,x=ay
对于x轴
注意是变换之前a=x/y => x=ay
x’=k1x
y’=k2y
x’=y’=1(变换之后的x’,y’坐标都为1)
k1x=k2y
k1=k2 *
y
x
\frac{y}{x}
xy
a=
x
y
\frac{x}{y}
yx
k1=
k
2
a
\frac{k2}{a}
ak2
k2=
1
S
i
z
e
\frac{1}{Size}
Size1
k1=
1
A
s
p
e
c
t
∗
S
i
z
e
\frac{1}{Aspect*Size}
Aspect∗Size1
w=ah为什么不是k1=ak2,而是k1=k2/a,这是因为知道的是变换之前的比值,变换之后x’=y’,
假设是横屏,宽度大于高度,即a>1,x>y,想要x’=y’,则x’=kx,k<1,即1/a
对于z轴,观察长方体变换前后的长度,z=Far-Near,z’=2,z轴要翻转,乘以-1,
Far-Near=>2
z’=k3z,
k3=
−
2
F
a
r
−
N
e
a
r
-\frac{2}{Far-Near}
−Far−Near2
矩阵:
[
1
S
i
z
e
0
0
0
0
1
A
s
p
e
c
t
S
i
z
e
0
0
0
0
−
2
F
a
r
−
N
e
a
r
?
0
0
0
1
]
\begin{bmatrix} \frac{1}{Size}& 0 & 0 & 0 \\ 0 & \frac{1}{AspectSize} & 0&0\\ 0 & 0 & -\frac{2}{Far-Near}&?\\ 0 & 0 & 0& 1\\ \end{bmatrix}
Size10000AspectSize10000−Far−Near2000?1
再考虑z轴上的平移就可以求出完整的矩阵了
平移,由2部分组成,如上图所示,在经过缩放后的空间观察,
一部分是,摄像机到裁剪平面的距离,另一部分是正方体长度的一半
摄像机到裁剪平面的距离,由于经过缩放,大小不是Near,而是Near*k3=
−
2
N
e
a
r
F
a
r
−
N
e
a
r
-\frac{2Near}{Far-Near}
−Far−Near2Near
正方体长度的一半,注意z轴翻转了,1,
−
2
N
e
a
r
F
a
r
−
N
e
a
r
-\frac{2Near}{Far-Near}
−Far−Near2Near-1=
−
2
N
e
a
r
F
a
r
−
N
e
a
r
-\frac{2Near}{Far-Near}
−Far−Near2Near-
F
a
r
−
N
e
a
r
F
a
r
−
N
e
a
r
\frac{Far-Near}{Far-Near}
Far−NearFar−Near
=
−
N
e
a
r
−
F
a
r
F
a
r
−
N
e
a
r
\frac{-Near-Far}{Far-Near}
Far−Near−Near−Far=
−
F
a
r
+
N
e
a
r
F
a
r
−
N
e
a
r
-\frac{Far+Near}{Far-Near}
−Far−NearFar+Near(和书上的写法保持一致)
至此,正交矩阵就推导出来了
[
1
S
i
z
e
0
0
0
0
1
A
s
p
e
c
t
S
i
z
e
0
0
0
0
−
2
F
a
r
−
N
e
a
r
−
F
a
r
+
N
e
a
r
F
a
r
−
N
e
a
r
0
0
0
1
]
\begin{bmatrix} \frac{1}{Size}& 0 & 0 & 0 \\ 0 & \frac{1}{AspectSize} & 0&0\\ 0 & 0 & -\frac{2}{Far-Near}&-\frac{Far+Near}{Far-Near}\\ 0 & 0 & 0& 1\\ \end{bmatrix}
Size10000AspectSize10000−Far−Near2000−Far−NearFar+Near1
如果不理解矩阵为什么要怎么写,可以查查关于缩放旋转平移,3大矩阵的资料
透视投影
- 基本概念:
NearHeight: 近裁剪面的高度
FarHeight: 远裁剪面的高度
Near:摄像机离近裁剪面的距离
Far:摄像机离近裁剪面的距离
FOV:Field of View,视野范围
为什么上面的变换不能像正交变换一样,直接转化为[-1,1]标准化的立方体
而是要变换为一个棱台,这是因为矩阵的线性变换,可以将长方体变换为立方体,
无法将一个棱台转换为立方体,棱台转换为立方体需要非线性变换函数,
4×4的变换矩阵,只能对空间进行缩放旋转平移,空间中任意2个原本平行的直线变换后仍然平行,这3大变换显然不能将棱台转换为立方体.因为棱台=>正方体,棱台的两侧的直线不平行=>平行,线性变换无法实现
将w存储变换之前的z,将变换之后的点xyz都除以w,就都变换到[-1,1],此变换是非线性的,缩放值是不固定的,对
不同的平面(平行于xOy的平面),缩放值为平面之前离摄像机的距离
这也是为什么变换后xy有Near,Far
上面的变换可以分为以下几步
- 对视锥体进行缩放,让它的xyzw等于缩放之后的xyzw
- 对视锥体的z方向进行平移
- 翻转z轴
tan
F
O
V
2
\frac{FOV}{2}
2FOV=
n
e
a
r
H
e
i
g
h
t
2
N
e
a
r
\frac{\frac{nearHeight}{2}}{Near}
Near2nearHeight ①
tan
F
O
V
2
\frac{FOV}{2}
2FOV等于近裁剪面的高度的一半/Near
Aspect,摄像机横纵比,Aspect=
N
e
a
r
W
i
d
t
h
N
e
a
r
H
e
i
g
h
t
{\frac{NearWidth}{NearHeight}}
NearHeightNearWidth
先考虑缩放
y轴的缩放,对于下图点2.y来说
N
e
a
r
H
e
i
g
h
t
2
\frac{NearHeight}{2}
2NearHeight=>Near
对于y轴,由
n
e
a
r
H
e
i
g
h
t
2
=
>
N
e
a
r
\frac{nearHeight}{2}=>Near
2nearHeight=>Near,
即将原来的y乘以
N
e
a
r
N
e
a
r
H
e
i
g
h
t
2
\frac{Near}{\frac{NearHeight}{2}}
2NearHeightNear=>y’
y*
N
e
a
r
N
e
a
r
H
e
i
g
h
t
2
\frac{Near}{\frac{NearHeight}{2}}
2NearHeightNear=y’
y’=ky,k=
N
e
a
r
N
e
a
r
H
e
i
g
h
t
2
\frac{Near}{\frac{NearHeight}{2}}
2NearHeightNear②
由①=>cot
F
O
V
2
\frac{FOV}{2}
2FOV=
N
e
a
r
n
e
a
r
H
e
i
g
h
t
2
\frac{Near}{\frac{nearHeight}{2}}
2nearHeightNear③
由②③得k=cot
F
O
V
2
\frac{FOV}{2}
2FOV
怎么直观理解cot
F
O
V
2
\frac{FOV}{2}
2FOV,
其实就是点2.y变换前后的缩放,
恰好等于Near/近裁剪面的高度的一半,即cot
F
O
V
2
\frac{FOV}{2}
2FOV
因为,NearWidth=Aspect*NearHeight,w=ah
NearHeight=
N
e
a
r
W
i
d
t
h
A
s
p
e
c
t
\frac{NearWidth}{Aspect}
AspectNearWidth,h=w/a
对于x轴的缩放=y轴的缩放/Aspect
对于x轴,由NearWidth/2=>Near,即将原来的x乘以
N
e
a
r
N
e
a
r
W
i
d
t
h
2
\frac{Near}{\frac{NearWidth}{2}}
2NearWidthNear
w=ah为什么不是k1=ak2,而是k1=k2/a,这是因为知道的是变换之前的比值,变换之后x’=y’,
假设是横屏,宽度大于高度,即a>1,x>y,想要x’=y’,则x’=kx,k<1,即1/a
对于x轴的缩放有2种方式推导
方法1:
注意是变换之前a=x/y => x=ay
x’=k1x
y’=k2y
x’=y’=Near(变换之后的x’,y’坐标都为Near)
k1x=k2y
k1=k2 *
y
x
\frac{y}{x}
xy
a=
x
y
\frac{x}{y}
yx
k1=
k
2
a
\frac{k2}{a}
ak2
k2=cot
F
O
V
2
\frac{FOV}{2}
2FOV
k1=
c
o
t
F
O
V
2
A
s
p
e
c
t
\frac{cot\frac{FOV}{2}}{Aspect}
Aspectcot2FOV
方法2:
x *
N
e
a
r
N
e
a
r
W
i
d
t
h
2
\frac{Near}{\frac{NearWidth}{2}}
2NearWidthNear=x’,k2=
N
e
a
r
N
e
a
r
W
i
d
t
h
2
\frac{Near}{\frac{NearWidth}{2}}
2NearWidthNear
②=>
N
e
a
r
h
2
\frac{Near}{\frac{h}{2}}
2hNear=>
N
e
a
r
w
/
a
2
\frac{Near}{\frac{w/a}{2}}
2w/aNear=>
N
e
a
r
w
2
a
\frac{Near}{\frac{w}{2a}}
2awNear
cot
F
O
V
2
\frac{FOV}{2}
2FOV=
N
e
a
r
n
e
a
r
H
e
i
g
h
t
2
\frac{Near}{\frac{nearHeight}{2}}
2nearHeightNear③
=>cot
F
O
V
2
\frac{FOV}{2}
2FOV=
N
e
a
r
w
2
a
\frac{Near}{\frac{w}{2a}}
2awNear
=>
c
o
t
F
O
V
2
a
\frac{cot\frac{FOV}{2}}{a}
acot2FOV=
N
e
a
r
w
2
\frac{Near}{\frac{w}{2}}
2wNear
k2=
N
e
a
r
w
2
\frac{Near}{\frac{w}{2}}
2wNear=
c
o
t
F
O
V
2
a
\frac{cot\frac{FOV}{2}}{a}
acot2FOV
所以,x,y的缩放倍数已经得到
[
c
o
t
F
O
V
2
A
s
p
e
c
t
0
0
0
0
c
o
t
F
O
V
2
0
0
0
0
?
?
0
0
?
0
]
\begin{bmatrix} \frac{cot\frac{FOV}{2}}{Aspect} & 0 & 0 & 0 \\ 0 & cot\frac{FOV}{2} & 0&0\\ 0 & 0 & ?&?\\ 0 & 0 & ?& 0\\ \end{bmatrix}
Aspectcot2FOV0000cot2FOV0000??00?0
与上面的图片一样,方便查看图片
下面讲解怎么得到z轴的缩放
对于视锥体,在z方向,之前视锥体的长度为Far-Near,变换之后的大小为Far+Near,
所以k3=
F
a
r
+
N
e
a
r
F
a
r
−
N
e
a
r
\frac{Far+Near}{Far-Near}
Far−NearFar+Near,对z轴进行翻转,k3=-
F
a
r
+
N
e
a
r
F
a
r
−
N
e
a
r
\frac{Far+Near}{Far-Near}
Far−NearFar+Near
下面讲解z轴的平移和z轴的翻转,平移分两部分,在经过缩放后的空间观察,
一部分是变换后的点2的z,即z’2 =k3Near,另一部分是Near
z’=k3z,k3=
F
a
r
+
N
e
a
r
N
e
a
r
−
F
a
r
\frac{Far+Near}{Near-Far}
Near−FarFar+Near,Near
F
a
r
+
N
e
a
r
N
e
a
r
−
F
a
r
\frac{Far+Near}{Near-Far}
Near−FarFar+Near=
N
e
a
r
∗
F
a
r
+
N
e
a
r
2
N
e
a
r
−
F
a
r
\frac{Near*Far+Near^{2}}{Near-Far}
Near−FarNear∗Far+Near2
加上变换之后的,-Near(因为z轴的翻转),
N
e
a
r
∗
F
a
r
+
N
e
a
r
2
N
e
a
r
−
F
a
r
\frac{Near*Far+Near^{2}}{Near-Far}
Near−FarNear∗Far+Near2-Near=
N
e
a
r
∗
F
a
r
+
N
e
a
r
2
N
e
a
r
−
F
a
r
\frac{Near*Far+Near^{2}}{Near-Far}
Near−FarNear∗Far+Near2-
N
e
a
r
2
−
N
e
a
r
∗
F
a
r
N
e
a
r
−
F
a
r
\frac{Near^{2}-Near*Far}{Near-Far}
Near−FarNear2−Near∗Far=
2
∗
N
e
a
r
∗
F
a
r
N
e
a
r
−
F
a
r
\frac{2*Near*Far}{Near-Far}
Near−Far2∗Near∗Far
至此,缩放平移都完成了
要w保存之前的z,设置第4行3列为1即可
透视矩阵就推导出来了
[
c
o
t
F
O
V
2
A
s
p
e
c
t
0
0
0
0
c
o
t
F
O
V
2
0
0
0
0
−
F
a
r
+
N
e
a
r
F
a
r
−
N
e
a
r
−
2
∗
N
e
a
r
∗
F
a
r
F
a
r
−
N
e
a
r
0
0
1
0
]
\begin{bmatrix} \frac{cot\frac{FOV}{2}}{Aspect} & 0 & 0 & 0 \\ 0 & cot\frac{FOV}{2} & 0&0\\ 0 & 0 & -\frac{Far+Near}{Far-Near} & -\frac{2*Near*Far}{Far-Near} \\ 0 & 0 & 1& 0\\ \end{bmatrix}
Aspectcot2FOV0000cot2FOV0000−Far−NearFar+Near100−Far−Near2∗Near∗Far0