]> git.localhorst.tv Git - blank.git/blob - src/geometry.cpp
update light levels from border on neighbor change
[blank.git] / src / geometry.cpp
1 #include "geometry.hpp"
2
3 #include <limits>
4
5
6 namespace blank {
7
8 bool Intersection(
9         const Ray &ray,
10         const AABB &aabb,
11         const glm::mat4 &M,
12         float *dist,
13         glm::vec3 *normal
14 ) {
15         float t_min = 0.0f;
16         float t_max = std::numeric_limits<float>::infinity();
17         const glm::vec3 aabb_pos(M[3].x, M[3].y, M[3].z);
18         const glm::vec3 delta = aabb_pos - ray.orig;
19
20         glm::vec3 t1(t_min, t_min, t_min), t2(t_max, t_max, t_max);
21
22         { // X
23                 const glm::vec3 xaxis(M[0].x, M[0].y, M[0].z);
24                 const float e = glm::dot(xaxis, delta);
25                 const float f = glm::dot(ray.dir, xaxis);
26
27                 if (std::abs(f) > std::numeric_limits<float>::epsilon()) {
28                         t1.x = (e + aabb.min.x) / f;
29                         t2.x = (e + aabb.max.x) / f;
30
31                         t_min = std::max(t_min, std::min(t1.x, t2.x));
32                         t_max = std::min(t_max, std::max(t1.x, t2.x));
33
34                         if (t_max < t_min) {
35                                 return false;
36                         }
37                 } else {
38                         if (aabb.min.x - e < 0.0f || -aabb.max.x - e > 0.0f) {
39                                 return false;
40                         }
41                 }
42         }
43
44         { // Y
45                 const glm::vec3 yaxis(M[1].x, M[1].y, M[1].z);
46                 const float e = glm::dot(yaxis, delta);
47                 const float f = glm::dot(ray.dir, yaxis);
48
49                 if (std::abs(f) > std::numeric_limits<float>::epsilon()) {
50                         t1.y = (e + aabb.min.y) / f;
51                         t2.y = (e + aabb.max.y) / f;
52
53                         t_min = std::max(t_min, std::min(t1.y, t2.y));
54                         t_max = std::min(t_max, std::max(t1.y, t2.y));
55
56                         if (t_max < t_min) {
57                                 return false;
58                         }
59                 } else {
60                         if (aabb.min.y - e < 0.0f || -aabb.max.y - e > 0.0f) {
61                                 return false;
62                         }
63                 }
64         }
65
66         { // Z
67                 const glm::vec3 zaxis(M[2].x, M[2].y, M[2].z);
68                 const float e = glm::dot(zaxis, delta);
69                 const float f = glm::dot(ray.dir, zaxis);
70
71                 if (std::abs(f) > std::numeric_limits<float>::epsilon()) {
72                         t1.z = (e + aabb.min.z) / f;
73                         t2.z = (e + aabb.max.z) / f;
74
75                         t_min = std::max(t_min, std::min(t1.z, t2.z));
76                         t_max = std::min(t_max, std::max(t1.z, t2.z));
77
78                         if (t_max < t_min) {
79                                 return false;
80                         }
81                 } else {
82                         if (aabb.min.z - e < 0.0f || -aabb.max.z - e > 0.0f) {
83                                 return false;
84                         }
85                 }
86         }
87
88         glm::vec3 min_all(min(t1, t2));
89
90         if (dist) {
91                 *dist = t_min;
92         }
93         if (normal) {
94                 glm::vec4 norm(0.0f);
95                 if (min_all.x > min_all.y) {
96                         if (min_all.x > min_all.z) {
97                                 norm.x = t2.x < t1.x ? 1 : -1;
98                         } else {
99                                 norm.z = t2.z < t1.z ? 1 : -1;
100                         }
101                 } else if (min_all.y > min_all.z) {
102                         norm.y = t2.y < t1.y ? 1 : -1;
103                 } else {
104                         norm.z = t2.z < t1.z ? 1 : -1;
105                 }
106                 norm = M * norm;
107                 *normal = glm::vec3(norm);
108         }
109         return true;
110 }
111
112 bool CullTest(const AABB &box, const glm::mat4 &MVP) {
113         // transform corners into clip space
114         glm::vec4 corners[8] = {
115                 { box.min.x, box.min.y, box.min.z, 1.0f },
116                 { box.min.x, box.min.y, box.max.z, 1.0f },
117                 { box.min.x, box.max.y, box.min.z, 1.0f },
118                 { box.min.x, box.max.y, box.max.z, 1.0f },
119                 { box.max.x, box.min.y, box.min.z, 1.0f },
120                 { box.max.x, box.min.y, box.max.z, 1.0f },
121                 { box.max.x, box.max.y, box.min.z, 1.0f },
122                 { box.max.x, box.max.y, box.max.z, 1.0f },
123         };
124         for (glm::vec4 &corner : corners) {
125                 corner = MVP * corner;
126                 corner /= corner.w;
127         }
128
129         int hits[6] = { 0, 0, 0, 0, 0, 0 };
130
131         // check how many corners lie outside
132         for (const glm::vec4 &corner : corners) {
133                 if (corner.x >  1.0f) ++hits[0];
134                 if (corner.x < -1.0f) ++hits[1];
135                 if (corner.y >  1.0f) ++hits[2];
136                 if (corner.y < -1.0f) ++hits[3];
137                 if (corner.z >  1.0f) ++hits[4];
138                 if (corner.z < -1.0f) ++hits[5];
139         }
140
141         // if all corners are outside any given clip plane, the test is true
142         for (int hit : hits) {
143                 if (hit == 8) return true;
144         }
145
146         // otherwise the box might still get culled completely, but can't say for sure ;)
147         return false;
148 }
149
150 }