Broken KD

This commit is contained in:
Ben Kyd
2019-08-13 21:45:31 -07:00
parent 8b6aa8fdb8
commit bbcf81392c
10 changed files with 321 additions and 240 deletions

View File

@@ -5,215 +5,104 @@
#include "../definitions/primatives/primative.hpp"
#include "../definitions/primatives/triangle.hpp"
#include "../definitions/ray.hpp"
#include "bbox.hpp"
Box::Box() {
return;
#define MAX_TREE_DEPTH 64
#define TRIANGLES_PER_LEAF 20
bool autoSmooth;
int maxDepthSum;
int numNodes;
void KDTreeNode::InitLeaf(const std::vector<Triangle*>& triangles) {
axis = AXIS_NONE;
this->triangles = new std::vector<Triangle*>(triangles);
}
Box::Box(Triangle* object) {
min.x = std::numeric_limits<float>::max();
min.y = std::numeric_limits<float>::max();
min.z = std::numeric_limits<float>::max();
max.x = std::numeric_limits<float>::lowest();
max.y = std::numeric_limits<float>::lowest();
max.z = std::numeric_limits<float>::lowest();
ExtendTriangle(object);
void KDTreeNode::InitTreeNode(Axis axis, float splitPos) {
this->axis = axis;
this->splitPos = splitPos;
this->children = new KDTreeNode[2];
}
void Box::ExtendTriangle(Triangle* object) {
ExtendPoint(object->points[0]);
ExtendPoint(object->points[1]);
ExtendPoint(object->points[2]);
KDTreeNode::~KDTreeNode() {
if (axis == AXIS_NONE)
delete triangles;
else
delete [] children;
}
void Box::ExtendPoint(glm::vec3 p) {
if (p.x < min.x) min.x = p.x;
if (p.y < min.y) min.y = p.y;
if (p.z < min.z) min.z = p.z;
if (p.x > max.x) max.x = p.x;
if (p.y > max.y) max.y = p.y;
if (p.z > max.z) max.z = p.z;
}
int Box::LongestAxis() {
float diff_x = fabsf(max.x - min.x);
float diff_y = fabsf(max.y - min.y);
float diff_z = fabsf(max.z - min.z);
if (diff_x > diff_y && diff_x > diff_z){
return 0;
} else if (diff_y > diff_z) {
return 1;
} else {
return 2;
}
}
bool Box::Hit(Ray* ray) {
if (ray->origin.x >= min.x && ray->origin.x < max.x &&
ray->origin.y >= min.y && ray->origin.y < max.y &&
ray->origin.z >= min.z && ray->origin.z < max.z) {
return true;
}
float dirfrac_x = 1.0f / ray->direction.x;
float dirfrac_y = 1.0f / ray->direction.y;
float dirfrac_z = 1.0f / ray->direction.z;
float t1 = (min.x - ray->origin.x) * dirfrac_x;
float t2 = (max.x - ray->origin.x) * dirfrac_x;
float t3 = (min.y - ray->origin.y) * dirfrac_y;
float t4 = (max.y - ray->origin.y) * dirfrac_y;
float t5 = (min.z - ray->origin.z) * dirfrac_z;
float t6 = (max.z - ray->origin.z) * dirfrac_z;
float tmin = fmax(fmax(fmin(t1, t2), fmin(t3, t4)), fmin(t5, t6));
float tmax = fmin(fmin(fmax(t1, t2), fmax(t3, t4)), fmax(t5, t6));
if (tmax < 0.0f) {
return false;
}
if (tmin > tmax) {
return false;
}
return tmin > 0.0f;
}
KDTree* BuildKDTree(const std::vector<Triangle*>& triangles)
{
KDTree* node = new KDTree();
node->children = triangles;
if (triangles.size() == 0) {
return node;
void BuildKDTree(KDTreeNode* node, BBox bbox, std::vector<Triangle*>& triangleList, int depth) {
if (depth > MAX_TREE_DEPTH || int(triangleList.size()) < TRIANGLES_PER_LEAF) {
maxDepthSum += depth;
numNodes++;
std::cout << "leaf" << triangleList.size() << std::endl;
node->InitLeaf(triangleList);
return;
}
if (triangles.size() == 1) {
node->bounds = Box(triangles[0]);
node->child0 = new KDTree();
node->child1 = new KDTree();
node->child0->children = std::vector<Triangle*>();
node->child1->children = std::vector<Triangle*>();
return node;
}
node->bounds = Box(triangles[0]);
for (int i = 1; i < triangles.size(); i++) {
node->bounds.ExtendTriangle(triangles[i]);
}
glm::vec3 midpoint = glm::vec3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < triangles.size(); i++) {
midpoint = midpoint + ((triangles[i]->Midpoint()) * (1.0f / float(triangles.size())));
}
std::vector<Triangle*> bucket0;
std::vector<Triangle*> bucket1;
int axis = node->bounds.LongestAxis();
for (int i = 0; i < triangles.size(); i++) {
glm::vec3 temp_midpoint = triangles[i]->Midpoint();
if (axis == 0) {
if (midpoint.x >= temp_midpoint.x) {
bucket1.push_back(triangles[i]);
}
else {
bucket0.push_back(triangles[i]);
}
} else if (axis == 1) {
if (midpoint.y >= temp_midpoint.y) {
bucket1.push_back(triangles[i]);
} else {
bucket0.push_back(triangles[i]);
}
} else {
if (midpoint.z >= temp_midpoint.z) {
bucket1.push_back(triangles[i]);
} else {
bucket0.push_back(triangles[i]);
}
}
}
Axis axis = (Axis) (depth % 3);
float leftLimit = bbox.vmin[axis];
float rightLimit = bbox.vmax[axis];
if (bucket0.size() == 0 && bucket1.size() > 0) {
bucket0 = bucket1;
float optimalSplitPos = (leftLimit + rightLimit) * 0.5; // TODO: actually calculate a half decent split pos
BBox bboxLeft, bboxRight;
std::vector<Triangle*> trianglesLeft, trianglesRight;
bbox.Split(axis, optimalSplitPos, bboxLeft, bboxRight);
for (auto tri: triangleList) {
if (bboxLeft.IntersectTriangle(*tri))
trianglesLeft.push_back(tri);
if (bboxRight.IntersectTriangle(*tri))
trianglesRight.push_back(tri);
}
node->InitTreeNode(axis, optimalSplitPos);
BuildKDTree(&node->children[0], bboxLeft, trianglesLeft, depth + 1);
BuildKDTree(&node->children[1], bboxRight, trianglesRight, depth + 1);
}
if (bucket1.size() == 0 && bucket0.size() > 0) {
bucket1 = bucket0;
}
int matches = 0;
for (int i = 0; i < bucket0.size(); i++) {
for (int j = 0; j < bucket1.size(); j++) {
if (bucket0[i] == bucket1[j]) {
matches++;
bool KDIntersect(KDTreeNode* node, BBox& bbox, Ray& ray, Triangle*& intersect, float& t) {
if (node->axis == AXIS_NONE) {
bool found = false;
for (int i = 0; i > node->triangles->size(); i++) {
std::cout << "testing" << std::endl;
if ((*node->triangles)[i]->Intersect(ray, t)) {
intersect = (*node->triangles)[i];
return true;
}
}
}
float threshold = 0.5f;
if ((float)matches / float(bucket0.size()) < threshold &&
(float)matches / float(bucket1.size()) < threshold) {
node->child0 = BuildKDTree(bucket0);
node->child1 = BuildKDTree(bucket1);
return (found && bbox.Inside(ray.origin + ray.direction * t));
} else {
node->child0 = new KDTree();
node->child1 = new KDTree();
node->child0->children = std::vector<Triangle*>();
node->child1->children = std::vector<Triangle*>();
}
return node;
}
bool KDIntersect(KDTree* kd_tree1, Ray* ray, Triangle*& triangle_min,
float& t_min) {
if (kd_tree1->bounds.Hit(ray) > 0.0f) {
if (kd_tree1->child0->children.size() > 0 ||
kd_tree1->child1->children.size() > 0) {
bool a = KDIntersect(kd_tree1->child0, ray, triangle_min, t_min);
bool b = KDIntersect(kd_tree1->child1, ray, triangle_min, t_min);
return a || b;
} else {
bool did_hit_any = false;
for (int i = 0; i < kd_tree1->children.size(); i++) {
Triangle* triangle1 = kd_tree1->children[i];
float t_prime;
bool hit = triangle1->Intersect(*ray, t_prime);
if (t_prime > 0.0f && t_prime < t_min) {
did_hit_any = true;
t_min = t_prime;
triangle_min = triangle1;
}
}
return did_hit_any;
BBox childBBox[2];
bbox.Split(node->axis, node->splitPos, childBBox[0], childBBox[1]);
int childOrder[2] = { 0, 1 };
if (ray.origin[node->axis] > node->splitPos) {
std::swap(childOrder[0], childOrder[1]);
}
BBox& firstBB = childBBox[childOrder[0]];
BBox& secondBB = childBBox[childOrder[1]];
KDTreeNode& firstChild = node->children[childOrder[0]];
KDTreeNode& secondChild = node->children[childOrder[1]];
// if the ray intersects the common wall between the two sub-boxes, then it invariably
// intersects both boxes (we can skip the testIntersect() checks):
// (see http://raytracing-bg.net/?q=node/68 )
if (bbox.IntersectWall(node->axis, node->splitPos, ray)) {
if (KDIntersect(&firstChild, firstBB, ray, intersect, t)) return true;
return KDIntersect(&secondChild, secondBB, ray, intersect, t);
} else {
// if the wall isn't hit, then we intersect exclusively one of the sub-boxes;
// test one, if the test fails, then it's in the other:
if (firstBB.TestIntersect(ray))
return KDIntersect(&firstChild, firstBB, ray, intersect, t);
else
return KDIntersect(&secondChild, secondBB, ray, intersect, t);
}
return false;
}
return false;
}