OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Frustum.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2014-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "Frustum.h"
22 #include "AABB.h"
23 
25 
27 Frustum::Frustum(const mat4& view_projection)
28 {
29  // Frustum planes are in world space.
30  mat4 inv = mat_inverse(view_projection);
31 
32  // Get world-space coordinates for clip-space bounds.
33  vec4 lbn = inv * vec4(-1, -1, -1, 1);
34  vec4 ltn = inv * vec4(-1, 1, -1, 1);
35  vec4 lbf = inv * vec4(-1, -1, 1, 1);
36  vec4 rbn = inv * vec4( 1, -1, -1, 1);
37  vec4 rtn = inv * vec4( 1, 1, -1, 1);
38  vec4 rbf = inv * vec4( 1, -1, 1, 1);
39  vec4 rtf = inv * vec4( 1, 1, 1, 1);
40 
41  // Divide by w.
42  vec3 lbn_pos = vec_project(lbn);
43  vec3 ltn_pos = vec_project(ltn);
44  vec3 lbf_pos = vec_project(lbf);
45  vec3 rbn_pos = vec_project(rbn);
46  vec3 rtn_pos = vec_project(rtn);
47  vec3 rbf_pos = vec_project(rbf);
48  vec3 rtf_pos = vec_project(rtf);
49 
50  // Get plane normals for all sides of frustum.
51  vec3 left_normal = vec_normalize(vec_cross(lbf_pos - lbn_pos, ltn_pos - lbn_pos));
52  vec3 right_normal = vec_normalize(vec_cross(rtn_pos - rbn_pos, rbf_pos - rbn_pos));
53  vec3 top_normal = vec_normalize(vec_cross(ltn_pos - rtn_pos, rtf_pos - rtn_pos));
54  vec3 bottom_normal = vec_normalize(vec_cross(rbf_pos - rbn_pos, lbn_pos - rbn_pos));
55  vec3 near_normal = vec_normalize(vec_cross(ltn_pos - lbn_pos, rbn_pos - lbn_pos));
56  vec3 far_normal = vec_normalize(vec_cross(rtf_pos - rbf_pos, lbf_pos - rbf_pos));
57 
58  // Plane equations compactly represent a plane in 3D space.
59  // We want a way to compute the distance to the plane while preserving the sign to know which side we're on.
60  // Let:
61  // O: an arbitrary point on the plane
62  // N: the normal vector for the plane, pointing in the direction
63  // we want to be "positive".
64  // X: Position we want to check.
65  //
66  // Distance D to the plane can now be expressed as a simple operation:
67  // D = dot((X - O), N) = dot(X, N) - dot(O, N)
68  //
69  // We can reduce this to one dot product by assuming that X is four-dimensional (4th component = 1.0).
70  // The normal can be extended to four dimensions as well:
71  // X' = vec4(X, 1.0)
72  // N' = vec4(N, -dot(O, N))
73  //
74  // The expression now reduces to: D = dot(X', N')
75  planes[0] = vec4(near_normal, -vec_dot(near_normal, lbn_pos)); // Near
76  planes[1] = vec4(far_normal, -vec_dot(far_normal, lbf_pos)); // Far
77  planes[2] = vec4(left_normal, -vec_dot(left_normal, lbn_pos)); // Left
78  planes[3] = vec4(right_normal, -vec_dot(right_normal, rbn_pos)); // Right
79  planes[4] = vec4(top_normal, -vec_dot(top_normal, ltn_pos)); // Top
80  planes[5] = vec4(bottom_normal, -vec_dot(bottom_normal, lbn_pos)); // Bottom
81 }
83 
85 bool Frustum::intersects_aabb(const AABB& aabb) const
86 {
87  // If all corners of an axis-aligned bounding box are on the "wrong side" (negative distance)
88  // of at least one of the frustum planes, we can safely cull the mesh.
89  vec4 corners[8];
90  for (unsigned int c = 0; c < 8; c++)
91  {
92  // Require 4-dimensional coordinates for plane equations.
93  corners[c] = vec4(aabb.corner(c), 1.0f);
94  }
95 
96  for (unsigned int p = 0; p < 6; p++)
97  {
98  bool inside_plane = false;
99  for (unsigned int c = 0; c < 8; c++)
100  {
101  // If dot product > 0, we're "inside" the frustum plane,
102  // otherwise, outside.
103  if (vec_dot(corners[c], planes[p]) > 0.0f)
104  {
105  inside_plane = true;
106  break;
107  }
108  }
109 
110  if (!inside_plane)
111  return false;
112  }
113 
114  return true;
115 }
bool intersects_aabb(const AABB &aabb) const
[Compute plane equations]
Definition: Frustum.cpp:85
Frustum()
Definition: Frustum.cpp:24
Definition: matrix.h:51
float vec_dot(const T &a, const T &b)
Definition: vector_math.h:289
vec3 vec_cross(const vec3 &a, const vec3 &b)
Definition: vector_math.h:280
Definition: matrix.h:75
vec4 planes[6]
Definition: Frustum.h:37
vec3 corner(unsigned int index) const
Definition: AABB.cpp:34
Definition: matrix.h:104
mat4 mat_inverse(const mat4 &a)
Definition: vector_math.h:430
T vec_normalize(const T &vec)
Definition: vector_math.h:304
Definition: mesh.hpp:39
vec3 vec_project(const vec4 &vec)
Definition: vector_math.h:333