上图是3D渲染过程中的空间变换过程,这里主要讨论观察空间到裁剪空间的转换。
由上图可知,经过观察变换后,空间变换为观察空间,也就是以摄像机坐标为原点的空间,这是接下来推导的前提。
下图是一个视锥体,在视锥体范围内的物体为可视的,不在视锥体内的为不可视。
我们有两个任务:
1、判断一个点是否在视锥体内(用于裁剪超出屏幕的点)。
2、计算顶点在裁剪空间上的坐标。
我们先忘掉矩阵的概念,只用基本的三维几何知识完成第一点。
先假定一个场景如下图:
已知以下参数:
fov:视锥体上下两个截面的夹角,此参数由设定摄像机参数时给定了
n:近截面z轴坐标,此参数由设定摄像机参数时给定了
f:远截面z轴坐标,此参数由设定摄像机参数时给定了
aspect:屏幕宽高比,此参数由设定摄像机参数时给定了
H:平行于远截面,并且经过P点的平面的高的一半,可通过计算得出
由此,我们只需要判断P点的y轴坐标除以H是否大于1(当y为负时是否小于-1),即可知道P点是否在y轴方向上超出了视椎体。同理可求出x轴。
下面先求y方向。
H
=
z
∗
t
a
n
(
f
o
v
/
2
)
H=z*tan(fov/2)
H=z∗tan(fov/2)
y
/
H
=
y
/
z
∗
t
a
n
(
f
o
v
/
2
)
y/H=y/z*tan(fov/2)
y/H=y/z∗tan(fov/2)
接下来求x方向,假设经过此P点截面的宽度为W
W
=
a
s
p
e
c
t
∗
H
W=aspect*H
W=aspect∗H
W
=
a
s
p
e
c
t
∗
z
∗
t
a
n
(
f
o
v
/
2
)
W=aspect*z*tan(fov/2)
W=aspect∗z∗tan(fov/2)
x
/
W
=
x
/
(
a
s
p
e
c
t
∗
z
∗
t
a
n
(
f
o
v
/
2
)
)
x/W=x/(aspect*z*tan(fov/2))
x/W=x/(aspect∗z∗tan(fov/2))
最后求z方向
(
z
−
n
)
/
(
f
−
n
)
(z-n)/(f-n)
(z−n)/(f−n)
我们已经获得计算点是否在视锥体内的计算方式,现在我们把它转换为矩阵的形式,设M为我们要求的转换矩阵,可得:
M
⋅
[
x
y
z
1
]
=
[
x
a
s
p
e
c
t
∗
z
∗
t
a
n
(
f
o
v
/
2
)
y
z
∗
t
a
n
(
f
o
v
/
2
)
(
z
−
n
)
/
(
f
−
n
)
1
]
M \cdot \left[\begin{matrix} x \\ y \\ z \\ 1 \end{matrix}\right] = \left[\begin{matrix} \frac{x}{aspect*z*tan(fov/2)} \\ \frac{y}{z*tan(fov/2)} \\ (z-n)/(f-n) \\ 1 \end{matrix} \right]
M⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡aspect∗z∗tan(fov/2)xz∗tan(fov/2)y(z−n)/(f−n)1⎦⎥⎥⎤
[
m
00
m
01
m
02
m
03
m
10
m
11
m
12
m
13
m
20
m
21
m
22
m
23
m
30
m
31
m
32
m
33
]
⋅
[
x
y
z
1
]
=
[
x
a
s
p
e
c
t
∗
z
∗
t
a
n
(
f
o
v
/
2
)
y
z
∗
t
a
n
(
f
o
v
/
2
)
(
z
−
n
)
/
(
f
−
n
)
1
]
\left[ \begin{matrix} m_{00} & m_{01} & m_{02} & m_{03}\\ m_{10} & m_{11} & m_{12} & m_{13} \\ m_{20} & m_{21} & m_{22} & m_{23} \\ m_{30} & m_{31} & m_{32} & m_{33} \end{matrix} \right] \cdot \left[\begin{matrix} x \\ y \\ z \\ 1 \end{matrix}\right] = \left[\begin{matrix} \frac{x}{aspect*z*tan(fov/2)} \\ \frac{y}{z*tan(fov/2)} \\ (z-n)/(f-n) \\ 1 \end{matrix} \right]
⎣⎢⎢⎡m00m10m20m30m01m11m21m31m02m12m22m32m03m13m23m33⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡aspect∗z∗tan(fov/2)xz∗tan(fov/2)y(z−n)/(f−n)1⎦⎥⎥⎤
我们发现求解 m 00 ∗ x + m 01 ∗ y + m 02 ∗ z + m 03 = x z ∗ a s p e c t ∗ t a n ( f o v / 2 ) m_{00}*x + m_{01}*y + m_{02}*z + m_{03} = \frac{x}{z*aspect*tan(fov/2)} m00∗x+m01∗y+m02∗z+m03=z∗aspect∗tan(fov/2)x很难找出合适的 m 00 m_{00} m00和 m 02 m_{02} m02,因为左边x和z是以加法的形式相邻,右边z确成为了x的分母。
解决方法:将右边的齐次坐标每一项乘以z,所以有:
[
m
00
m
01
m
02
m
03
m
10
m
11
m
12
m
13
m
20
m
21
m
22
m
23
m
30
m
31
m
32
m
33
]
⋅
[
x
y
z
1
]
=
[
x
a
s
p
e
c
t
∗
t
a
n
(
f
o
v
/
2
)
y
t
a
n
(
f
o
v
/
2
)
z
∗
(
z
−
n
)
/
(
f
−
n
)
z
]
\left[ \begin{matrix} m_{00} & m_{01} & m_{02} & m_{03}\\ m_{10} & m_{11} & m_{12} & m_{13} \\ m_{20} & m_{21} & m_{22} & m_{23} \\ m_{30} & m_{31} & m_{32} & m_{33} \end{matrix} \right] \cdot \left[\begin{matrix} x \\ y \\ z \\ 1 \end{matrix}\right] = \left[\begin{matrix} \frac{x}{aspect*tan(fov/2)} \\ \frac{y}{tan(fov/2)} \\ z*(z-n)/(f-n) \\ z \end{matrix} \right]
⎣⎢⎢⎡m00m10m20m30m01m11m21m31m02m12m22m32m03m13m23m33⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡aspect∗tan(fov/2)xtan(fov/2)yz∗(z−n)/(f−n)z⎦⎥⎥⎤
所以可以求得矩阵为:
[
1
a
s
p
e
c
t
∗
t
a
n
(
f
o
v
/
2
)
0
0
0
0
1
t
a
n
(
f
o
v
/
2
)
0
0
0
0
m
22
m
23
0
0
1
0
]
\left[ \begin{matrix} \frac{1}{aspect*tan(fov/2)} & 0 & 0 & 0\\ 0 & \frac{1}{tan(fov/2)} & 0 & 0 \\ 0 & 0 & m_{22} & m_{23} \\ 0 & 0 & 1 & 0 \end{matrix} \right]
⎣⎢⎢⎡aspect∗tan(fov/2)10000tan(fov/2)10000m22100m230⎦⎥⎥⎤
m 22 ∗ z + m 23 = z ∗ ( z − n ) / ( f − n ) m_{22}*z + m_{23} = z*(z-n)/(f-n) m22∗z+m23=z∗(z−n)/(f−n)
我们知道,当 z = n z=n z=n时, ( z − n ) / ( f − n ) = − 1 (z-n)/(f-n)=-1 (z−n)/(f−n)=−1 所以 m 22 ∗ n + m 23 = − n m_{22}*n + m_{23} = -n m22∗n+m23=−n
当 z = f z=f z=f时, ( z − n ) / ( f − n ) = 1 (z-n)/(f-n)=1 (z−n)/(f−n)=1 所以 m 22 ∗ f + m 23 = f m_{22}*f + m_{23} = f m22∗f+m23=f
联 立 { m 22 ∗ n + m 23 = − n m 22 ∗ f + m 23 = f 联立 \begin{cases} m_{22}*n + m_{23} = -n \\ m_{22}*f + m_{23} = f \end{cases} 联立{m22∗n+m23=−nm22∗f+m23=f
求 得 { m 22 = − f − n n − f m 23 = 2 ∗ f ∗ n n − f 求得 \begin{cases} m_{22} = \frac{-f-n}{n-f} \\ m_{23} = \frac{2*f*n}{n-f} \end{cases} 求得{m22=n−f−f−nm23=n−f2∗f∗n
最后求得投影矩阵为:
[
1
a
s
p
e
c
t
∗
t
a
n
(
f
o
v
/
2
)
0
0
0
0
1
t
a
n
(
f
o
v
/
2
)
0
0
0
0
−
f
−
n
n
−
f
2
∗
f
∗
n
n
−
f
0
0
1
0
]
\left[ \begin{matrix} \frac{1}{aspect*tan(fov/2)} & 0 & 0 & 0\\ 0 & \frac{1}{tan(fov/2)} & 0 & 0 \\ 0 & 0 & \frac{-f-n}{n-f} & \frac{2*f*n}{n-f} \\ 0 & 0 & 1 & 0 \end{matrix} \right]
⎣⎢⎢⎢⎡aspect∗tan(fov/2)10000tan(fov/2)10000n−f−f−n100n−f2∗f∗n0⎦⎥⎥⎥⎤
注意,通过此矩阵转换后的坐标是齐次坐标,只要除以w分量,根据结果就可以判断是否在[-1,1]范围内,也就是该点是否在视椎体内。
透视投影矩阵只是为了获得一个齐次坐标,为投影做准备,实际不进行真正的投影,真正的屏幕投影是在下一个阶段执行的。
相较于https://www.cnblogs.com/bluebean/p/5276111.html,本文是用另外一种几何思路推导透视投影矩阵,可以互相参考。