158 lines
5.3 KiB
C++
158 lines
5.3 KiB
C++
#include "bbox.hpp"
|
|
|
|
#include "../definitions/ray.hpp"
|
|
#include "../definitions/primatives/triangle.hpp"
|
|
|
|
BBox::BBox() {}
|
|
|
|
void BBox::MakeEmpty() {
|
|
vmin = {+INFINITY, +INFINITY, +INFINITY};
|
|
vmax = {-INFINITY, -INFINITY, -INFINITY};
|
|
}
|
|
|
|
void BBox::Add(glm::vec3 vec) {
|
|
vmin.x = std::min(vmin.x, vec.x); vmax.x = std::max(vmax.x, vec.x);
|
|
vmin.y = std::min(vmin.y, vec.y); vmax.y = std::max(vmax.y, vec.y);
|
|
vmin.z = std::min(vmin.z, vec.z); vmax.z = std::max(vmax.z, vec.z);
|
|
}
|
|
|
|
bool BBox::Inside(glm::vec3 v) {
|
|
return (vmin.x - 1e-6 <= v.x && v.x <= vmax.x + 1e-6 &&
|
|
vmin.y - 1e-6 <= v.y && v.y <= vmax.y + 1e-6 &&
|
|
vmin.z - 1e-6 <= v.z && v.z <= vmax.z + 1e-6);
|
|
}
|
|
|
|
bool BBox::TestIntersect(Ray& ray) {
|
|
if (Inside(ray.origin)) return true;
|
|
for (int dim = 0; dim < 3; dim++) {
|
|
if ((ray.direction[dim] < 0 && ray.origin[dim] < vmin[dim]) || (ray.direction[dim] > 0 && ray.origin[dim] > vmax[dim])) continue;
|
|
if (fabs(ray.direction[dim]) < 1e-9) continue;
|
|
float mul = ray.rdirection[dim];
|
|
int u = (dim == 0) ? 1 : 0;
|
|
int v = (dim == 2) ? 1 : 2;
|
|
float dist, x, y;
|
|
dist = (vmin[dim] - ray.origin[dim]) * mul;
|
|
if (dist < 0) continue;
|
|
|
|
x = ray.origin[u] + ray.direction[u] * dist;
|
|
if (vmin[u] <= x && x <= vmax[u]) {
|
|
y = ray.origin[v] + ray.direction[v] * dist;
|
|
if (vmin[v] <= y && y <= vmax[v]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
dist = (vmax[dim] - ray.origin[dim]) * mul;
|
|
if (dist < 0) continue;
|
|
x = ray.origin[u] + ray.direction[u] * dist;
|
|
if (vmin[u] <= x && x <= vmax[u]) {
|
|
y = ray.origin[v] + ray.direction[v] * dist;
|
|
if (vmin[v] <= y && y <= vmax[v]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
float BBox::ClosestIntersection(Ray& ray) {
|
|
if (Inside(ray.origin)) return 0;
|
|
float minDist = INFINITY;
|
|
for (int dim = 0; dim < 3; dim++) {
|
|
if ((ray.direction[dim] < 0 && ray.origin[dim] < vmin[dim]) || (ray.direction[dim] > 0 && ray.origin[dim] > vmax[dim])) continue;
|
|
if (fabs(ray.direction[dim]) < 1e-9) continue;
|
|
float mul = ray.rdirection[dim];
|
|
float xs[2] = { vmin[dim], vmax[dim] };
|
|
int u = (dim == 0) ? 1 : 0;
|
|
int v = (dim == 2) ? 1 : 2;
|
|
for (int j = 0; j < 2; j++) {
|
|
float dist = (xs[j] - ray.origin[dim]) * mul;
|
|
if (dist < 0) continue;
|
|
float x = ray.origin[u] + ray.direction[u] * dist;
|
|
if (vmin[u] <= x && x <= vmax[u]) {
|
|
float y = ray.origin[v] + ray.direction[v] * dist;
|
|
if (vmin[v] <= y && y <= vmax[v]) {
|
|
minDist = std::min(minDist, dist);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return minDist;
|
|
}
|
|
|
|
bool BBox::IntersectTriangle(Triangle& triangle) {
|
|
if (Inside(triangle.points[0]) || Inside(triangle.points[1]) || Inside(triangle.points[2])) return true;
|
|
Ray ray;
|
|
for (int i = 0; i < 3; i++) for (int j = i + 1; j < 3; j++) {
|
|
ray.origin = triangle.points[i];
|
|
ray.direction = triangle.points[j] - triangle.points[i];
|
|
ray.Update();
|
|
if (TestIntersect(ray)) {
|
|
ray.origin = triangle.points[j];
|
|
ray.direction = triangle.points[i] - triangle.points[j];
|
|
ray.Update();
|
|
if (TestIntersect(ray)) return true;
|
|
}
|
|
}
|
|
|
|
glm::vec3 AB = triangle.points[1] - triangle.points[0];
|
|
glm::vec3 AC = triangle.points[2] - triangle.points[0];
|
|
|
|
auto thing = [] (glm::vec3 a, glm::vec3 b) -> glm::vec3 {
|
|
return {
|
|
a.y * b.z - a.z * b.y,
|
|
a.z * b.x - a.x * b.z,
|
|
a.x * b.y - a.y * b.x
|
|
};
|
|
};
|
|
|
|
glm::vec3 ABcrossAC = thing(AB, AC);
|
|
|
|
auto multi = [] (glm::vec3 a, glm::vec3 b) -> float {
|
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
};
|
|
|
|
float D = multi(triangle.points[0], ABcrossAC);
|
|
|
|
for (int mask = 0; mask < 7; mask++) {
|
|
for (int j = 0; j < 3; j++) {
|
|
if (mask & (1 << j)) continue;
|
|
ray.origin = {(mask & 1) ? vmax.x : vmin.x, (mask & 2) ? vmax.y : vmin.y, (mask & 4) ? vmax.z : vmin.z};
|
|
glm::vec3 rayEnd = ray.origin;
|
|
rayEnd[j] = vmax[j];
|
|
if (signOf(multi(ray.origin, ABcrossAC - D)) != signOf(multi(rayEnd, ABcrossAC - D))) {
|
|
ray.direction = rayEnd - ray.origin;
|
|
ray.Update();
|
|
float t;
|
|
if (triangle.Intersect(ray, t)) return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void BBox::Split(Axis axis, float where, BBox& left, BBox& right) {
|
|
left = *this;
|
|
right = *this;
|
|
left.vmax[axis] = where;
|
|
right.vmin[axis] = where;
|
|
}
|
|
|
|
bool BBox::IntersectWall(Axis axis, float where, const Ray& ray) {
|
|
if (fabs(ray.direction[axis]) < 1e-9) return (fabs(ray.origin[axis] - where) < 1e-9);
|
|
int u = (axis == 0) ? 1 : 0;
|
|
int v = (axis == 2) ? 1 : 2;
|
|
float toGo = where - ray.origin[axis];
|
|
float rdirInAxis = ray.rdirection[axis];
|
|
|
|
if ((toGo * rdirInAxis) < 0) return false;
|
|
float d = toGo * rdirInAxis;
|
|
float tu = ray.origin[u] + ray.direction[u] * d;
|
|
if (vmin[u] <= tu && tu <= vmax[u]) {
|
|
float tv = ray.origin[v] + ray.direction[v] * d;
|
|
return (vmin[v] <= tv && tv <= vmax[v]);
|
|
}
|
|
return false;
|
|
}
|
|
|