从MVP矩阵快速提取视锥平面方程
从MVP矩阵快速提取视锥平面方程
本文提出了一种方法,可以直接从世界、观察以及投影矩阵中计算出Viewing Frustum的六个面。
这个算法不仅快速准确,而且具有普适性,他可以让我们从相机空间、世界空间或者物体空间快速确定Frustum planes。
我们先从投影矩阵开始,首先我们假设世界矩阵和观察矩阵都是单位矩阵。这就意味着相机位于世界坐标系下的原点,并且朝向Z轴的正方向。
至此,我们现在已经可以直接从投影矩阵中提取视锥体的左裁剪平面方程。这里我们需要注意的是,得到的平面方程式没有归一化的(平面的法线向量不是单位向量),而且平面的法线方向是指向平面内部的。这就是说,如果要判断 v 在左裁剪平面空间内部,那么必须满足 ax + by + cz + d > 0
。
重复以上几步,可推导出到其他的几个裁剪面,具体见下表
到目前为止,我们都是假设世界矩阵( world )和观察矩阵( view )都是单位化了的矩阵。但是,本算法并不受这种条件的限制,而是在任何条件下都能使用,且有以下结论:
- 如果矩阵 M 等于投影矩阵 P ( M = P ),那么算法给出的裁剪面是在相机空间(camera space)
- 如果矩阵 M 等于观察矩阵 V 和投影矩阵 P 的组合( M = V * P ),那么算法给出的裁剪面是在世界空间(world space)
- 如果矩阵 M 等于世界矩阵 W,观察矩阵 V 和投影矩阵 P 的组合( M = W* V * P ),那么算法给出的裁剪面是在物体空间(object space)
下面给出OpenGL中的代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
struct Matrix4x4
{
// The elements of the 4x4 matrix are stored in
// column-major order (see "OpenGL Programming Guide",
// 3rd edition, pp 106, glLoadMatrix).
float _11, _21, _31, _41;
float _12, _22, _32, _42;
float _13, _23, _33, _43;
float _14, _24, _34, _44;
};
void ExtractPlanesGL(
Plane * p_planes,
const Matrix4x4 & comboMatrix,
bool normalize)
{
// Left clipping plane
p_planes[0].a = comboMatrix._41 + comboMatrix._11;
p_planes[0].b = comboMatrix._42 + comboMatrix._12;
p_planes[0].c = comboMatrix._43 + comboMatrix._13;
p_planes[0].d = comboMatrix._44 + comboMatrix._14;
// Right clipping plane
p_planes[1].a = comboMatrix._41 - comboMatrix._11;
p_planes[1].b = comboMatrix._42 - comboMatrix._12;
p_planes[1].c = comboMatrix._43 - comboMatrix._13;
p_planes[1].d = comboMatrix._44 - comboMatrix._14;
// Top clipping plane
p_planes[2].a = comboMatrix._41 - comboMatrix._21;
p_planes[2].b = comboMatrix._42 - comboMatrix._22;
p_planes[2].c = comboMatrix._43 - comboMatrix._23;
p_planes[2].d = comboMatrix._44 - comboMatrix._24;
// Bottom clipping plane
p_planes[3].a = comboMatrix._41 + comboMatrix._21;
p_planes[3].b = comboMatrix._42 + comboMatrix._22;
p_planes[3].c = comboMatrix._43 + comboMatrix._23;
p_planes[3].d = comboMatrix._44 + comboMatrix._24;
// Near clipping plane
p_planes[4].a = comboMatrix._41 + comboMatrix._31;
p_planes[4].b = comboMatrix._42 + comboMatrix._32;
p_planes[4].c = comboMatrix._43 + comboMatrix._33;
p_planes[4].d = comboMatrix._44 + comboMatrix._34;
// Far clipping plane
p_planes[5].a = comboMatrix._41 - comboMatrix._31;
p_planes[5].b = comboMatrix._42 - comboMatrix._32;
p_planes[5].c = comboMatrix._43 - comboMatrix._33;
p_planes[5].d = comboMatrix._44 - comboMatrix._34;
// Normalize the plane equations, if requested
if (normalize == true)
{
NormalizePlane(p_planes[0]);
NormalizePlane(p_planes[1]);
NormalizePlane(p_planes[2]);
NormalizePlane(p_planes[3]);
NormalizePlane(p_planes[4]);
NormalizePlane(p_planes[5]);
}
}
DirectX中平面方程
Ref
http://www8.cs.umu.se/kurser/5DV180/VT18/lab/plane_extraction.pdf
本文由作者按照 CC BY 4.0 进行授权