]> git.lizzy.rs Git - dragonblocks3d.git/blob - lib/FrustumCull.h
Frustum & Backface Culling
[dragonblocks3d.git] / lib / FrustumCull.h
1 #include <glm/matrix.hpp>
2
3 class Frustum
4 {
5 public:
6         Frustum() {}
7
8         // m = ProjectionMatrix * ViewMatrix 
9         Frustum(glm::mat4 m);
10
11         // http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
12         bool IsBoxVisible(const glm::vec3& minp, const glm::vec3& maxp) const;
13
14 private:
15         enum Planes
16         {
17                 Left = 0,
18                 Right,
19                 Bottom,
20                 Top,
21                 Near,
22                 Far,
23                 Count,
24                 Combinations = Count * (Count - 1) / 2
25         };
26
27         template<Planes i, Planes j>
28         struct ij2k
29         {
30                 enum { k = i * (9 - i) / 2 + j - 1 };
31         };
32
33         template<Planes a, Planes b, Planes c>
34         glm::vec3 intersection(const glm::vec3* crosses) const;
35         
36         glm::vec4   m_planes[Count];
37         glm::vec3   m_points[8];
38 };
39
40 inline Frustum::Frustum(glm::mat4 m)
41 {
42         m = glm::transpose(m);
43         m_planes[Left]   = m[3] + m[0];
44         m_planes[Right]  = m[3] - m[0];
45         m_planes[Bottom] = m[3] + m[1];
46         m_planes[Top]    = m[3] - m[1];
47         m_planes[Near]   = m[3] + m[2];
48         m_planes[Far]    = m[3] - m[2];
49
50         glm::vec3 crosses[Combinations] = {
51                 glm::cross(glm::vec3(m_planes[Left]),   glm::vec3(m_planes[Right])),
52                 glm::cross(glm::vec3(m_planes[Left]),   glm::vec3(m_planes[Bottom])),
53                 glm::cross(glm::vec3(m_planes[Left]),   glm::vec3(m_planes[Top])),
54                 glm::cross(glm::vec3(m_planes[Left]),   glm::vec3(m_planes[Near])),
55                 glm::cross(glm::vec3(m_planes[Left]),   glm::vec3(m_planes[Far])),
56                 glm::cross(glm::vec3(m_planes[Right]),  glm::vec3(m_planes[Bottom])),
57                 glm::cross(glm::vec3(m_planes[Right]),  glm::vec3(m_planes[Top])),
58                 glm::cross(glm::vec3(m_planes[Right]),  glm::vec3(m_planes[Near])),
59                 glm::cross(glm::vec3(m_planes[Right]),  glm::vec3(m_planes[Far])),
60                 glm::cross(glm::vec3(m_planes[Bottom]), glm::vec3(m_planes[Top])),
61                 glm::cross(glm::vec3(m_planes[Bottom]), glm::vec3(m_planes[Near])),
62                 glm::cross(glm::vec3(m_planes[Bottom]), glm::vec3(m_planes[Far])),
63                 glm::cross(glm::vec3(m_planes[Top]),    glm::vec3(m_planes[Near])),
64                 glm::cross(glm::vec3(m_planes[Top]),    glm::vec3(m_planes[Far])),
65                 glm::cross(glm::vec3(m_planes[Near]),   glm::vec3(m_planes[Far]))
66         };
67
68         m_points[0] = intersection<Left,  Bottom, Near>(crosses);
69         m_points[1] = intersection<Left,  Top,    Near>(crosses);
70         m_points[2] = intersection<Right, Bottom, Near>(crosses);
71         m_points[3] = intersection<Right, Top,    Near>(crosses);
72         m_points[4] = intersection<Left,  Bottom, Far>(crosses);
73         m_points[5] = intersection<Left,  Top,    Far>(crosses);
74         m_points[6] = intersection<Right, Bottom, Far>(crosses);
75         m_points[7] = intersection<Right, Top,    Far>(crosses);
76
77 }
78
79 // http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
80 inline bool Frustum::IsBoxVisible(const glm::vec3& minp, const glm::vec3& maxp) const
81 {
82         // check box outside/inside of frustum
83         for (int i = 0; i < Count; i++)
84         {
85                 if ((glm::dot(m_planes[i], glm::vec4(minp.x, minp.y, minp.z, 1.0f)) < 0.0) &&
86                         (glm::dot(m_planes[i], glm::vec4(maxp.x, minp.y, minp.z, 1.0f)) < 0.0) &&
87                         (glm::dot(m_planes[i], glm::vec4(minp.x, maxp.y, minp.z, 1.0f)) < 0.0) &&
88                         (glm::dot(m_planes[i], glm::vec4(maxp.x, maxp.y, minp.z, 1.0f)) < 0.0) &&
89                         (glm::dot(m_planes[i], glm::vec4(minp.x, minp.y, maxp.z, 1.0f)) < 0.0) &&
90                         (glm::dot(m_planes[i], glm::vec4(maxp.x, minp.y, maxp.z, 1.0f)) < 0.0) &&
91                         (glm::dot(m_planes[i], glm::vec4(minp.x, maxp.y, maxp.z, 1.0f)) < 0.0) &&
92                         (glm::dot(m_planes[i], glm::vec4(maxp.x, maxp.y, maxp.z, 1.0f)) < 0.0))
93                 {
94                         return false;
95                 }
96         }
97
98         // check frustum outside/inside box
99         int out;
100         out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].x > maxp.x) ? 1 : 0); if (out == 8) return false;
101         out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].x < minp.x) ? 1 : 0); if (out == 8) return false;
102         out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].y > maxp.y) ? 1 : 0); if (out == 8) return false;
103         out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].y < minp.y) ? 1 : 0); if (out == 8) return false;
104         out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].z > maxp.z) ? 1 : 0); if (out == 8) return false;
105         out = 0; for (int i = 0; i<8; i++) out += ((m_points[i].z < minp.z) ? 1 : 0); if (out == 8) return false;
106
107         return true;
108 }
109
110 template<Frustum::Planes a, Frustum::Planes b, Frustum::Planes c>
111 inline glm::vec3 Frustum::intersection(const glm::vec3* crosses) const
112 {
113         float D = glm::dot(glm::vec3(m_planes[a]), crosses[ij2k<b, c>::k]);
114         glm::vec3 res = glm::mat3(crosses[ij2k<b, c>::k], -crosses[ij2k<a, c>::k], crosses[ij2k<a, b>::k]) *
115                 glm::vec3(m_planes[a].w, m_planes[b].w, m_planes[c].w);
116         return res * (-1.0f / D);
117 }