1 //
2 //  frustum.h
3 //  CubicVR2
4 //
5 //  Created by Charles J. Cliffe on 2013-02-22.
6 //  Copyright (c) 2013 Charles J. Cliffe. All rights reserved.
7 //
8 
9 #ifndef CubicVR2_frustum_h
10 #define CubicVR2_frustum_h
11 
12 #include <vector>
13 #include "cubic_types.h"
14 #include "mat4.h"
15 #include "vec3.h"
16 #include "vec4.h"
17 #include "plane.h"
18 
19 namespace CubicVR {
20 
21     enum frustum_plane { PLANE_LEFT, PLANE_RIGHT, PLANE_TOP, PLANE_BOTTOM, PLANE_NEAR, PLANE_FAR };
22 
23     struct frustum {
24         std::vector<vec4> planes;
25         vec4 sphere;
26 
frustumfrustum27         frustum() {
28             planes.resize(6);
29             for (int i = 0; i < 6; ++i) {
30                 planes[i] = vec4(0, 0, 0, 0);
31             } //for
32         } //Frustum::Constructor
33 
extractfrustum34         void extract(vec3 position, mat4 mvMatrix, mat4 pMatrix) {
35             mat4 comboMatrix = mat4::multiply(pMatrix, mvMatrix, true);
36 
37             // Left clipping plane
38             planes[PLANE_LEFT][0] = comboMatrix[3] + comboMatrix[0];
39             planes[PLANE_LEFT][1] = comboMatrix[7] + comboMatrix[4];
40             planes[PLANE_LEFT][2] = comboMatrix[11] + comboMatrix[8];
41             planes[PLANE_LEFT][3] = comboMatrix[15] + comboMatrix[12];
42 
43             // Right clipping plane
44             planes[PLANE_RIGHT][0] = comboMatrix[3] - comboMatrix[0];
45             planes[PLANE_RIGHT][1] = comboMatrix[7] - comboMatrix[4];
46             planes[PLANE_RIGHT][2] = comboMatrix[11] - comboMatrix[8];
47             planes[PLANE_RIGHT][3] = comboMatrix[15] - comboMatrix[12];
48 
49             // Top clipping plane
50             planes[PLANE_TOP][0] = comboMatrix[3] - comboMatrix[1];
51             planes[PLANE_TOP][1] = comboMatrix[7] - comboMatrix[5];
52             planes[PLANE_TOP][2] = comboMatrix[11] - comboMatrix[9];
53             planes[PLANE_TOP][3] = comboMatrix[15] - comboMatrix[13];
54 
55             // Bottom clipping plane
56             planes[PLANE_BOTTOM][0] = comboMatrix[3] + comboMatrix[1];
57             planes[PLANE_BOTTOM][1] = comboMatrix[7] + comboMatrix[5];
58             planes[PLANE_BOTTOM][2] = comboMatrix[11] + comboMatrix[9];
59             planes[PLANE_BOTTOM][3] = comboMatrix[15] + comboMatrix[13];
60 
61             // Near clipping plane
62             planes[PLANE_NEAR][0] = comboMatrix[3] + comboMatrix[2];
63             planes[PLANE_NEAR][1] = comboMatrix[7] + comboMatrix[6];
64             planes[PLANE_NEAR][2] = comboMatrix[11] + comboMatrix[10];
65             planes[PLANE_NEAR][3] = comboMatrix[15] + comboMatrix[14];
66 
67             // Far clipping plane
68             planes[PLANE_FAR][0] = comboMatrix[3] - comboMatrix[2];
69             planes[PLANE_FAR][1] = comboMatrix[7] - comboMatrix[6];
70             planes[PLANE_FAR][2] = comboMatrix[11] - comboMatrix[10];
71             planes[PLANE_FAR][3] = comboMatrix[15] - comboMatrix[14];
72 
73             for (unsigned int i = 0; i < 6; ++i) {
74                 planes[i] = vec4::normalize(planes[i]);
75             }
76 
77             //Sphere
78             __float fov = 1 / pMatrix[5];
79             __float znear = -planes[PLANE_NEAR][3];
80             __float zfar = planes[PLANE_FAR][3];
81             __float view_length = zfar - znear;
82             __float height = view_length * fov;
83             __float width = height;
84 
85             vec3 P(0, 0, znear + view_length * 0.5f);
86             vec3 Q(width, height, znear + view_length);
87             vec3 diff = vec3::subtract(P, Q);
88             __float diff_mag = vec3::length(diff);
89 
90             vec3 look_v = vec3(comboMatrix[3], comboMatrix[9], comboMatrix[10]);
91             __float look_mag = vec3::length(look_v);
92             look_v = vec3::multiply(look_v, 1 / look_mag);
93 
94             vec3 pos = vec3(position[0], position[1], position[2]);
95             pos = vec3::add(pos, vec3::multiply(look_v, view_length * 0.5f));
96             pos = vec3::add(pos, vec3::multiply(look_v, 1));
97 
98             sphere = vec4(pos[0], pos[1], pos[2], diff_mag);
99 
100         }; //Frustum::extract
101 
contains_spherefrustum102         int contains_sphere(vec4 sphere) {
103 
104             for (unsigned int i = 0; i < 6; ++i) {
105                 vec4 &p = planes[i];
106                 vec3 normal = vec3(p[0], p[1], p[2]);
107                 __float distance = vec3::dot(normal, vec3(sphere[0],sphere[1],sphere[2])) + p[3];
108 
109                 //OUT
110                 if (distance < -sphere[3]) {
111                     return -1;
112                 }
113 
114                 //INTERSECT
115                 if (fabs(distance) < sphere[3]) {
116                     return 0;
117                 }
118 
119             } //for
120             //IN
121             return 1;
122         }; //Frustum::contains_sphere
123 
contains_boxfrustum124         int contains_box(aabb bbox) {
125             int total_in = 0;
126 
127             vec3 points[8];
128 
129             points[0] = bbox.min;
130             points[1] = vec3(bbox.min[0], bbox.min[1], bbox.max[2]);
131             points[2] = vec3(bbox.min[0], bbox.max[1], bbox.min[2]);
132             points[3] = vec3(bbox.min[0], bbox.max[1], bbox.max[2]);
133             points[4] = vec3(bbox.max[0], bbox.min[1], bbox.min[2]);
134             points[5] = vec3(bbox.max[0], bbox.min[1], bbox.max[2]);
135             points[6] = vec3(bbox.max[0], bbox.max[1], bbox.min[2]);
136             points[7] = bbox.max;
137 
138             for (unsigned int i = 0; i < 6; ++i) {
139                 unsigned int in_count = 8;
140                 unsigned int point_in = 1;
141 
142                 for (unsigned int j = 0; j < 8; ++j) {
143                     if (plane::classifyPoint(planes[i], points[j]) == -1) {
144                         point_in = 0;
145                         --in_count;
146                     } //if
147                 } //for j
148 
149                 //OUT
150                 if (in_count == 0) {
151                     return -1;
152                 }
153 
154                 total_in += point_in;
155             } //for i
156             //IN
157             if (total_in == 6) {
158                 return 1;
159             }
160 
161             return 0;
162         }; //Frustum::contains_box
163 
164     };
165 }
166 
167 #endif
168