diff --git a/src/acceleration/accel.cpp b/src/acceleration/accel.cpp index e69de29..c415cc5 100644 --- a/src/acceleration/accel.cpp +++ b/src/acceleration/accel.cpp @@ -0,0 +1,74 @@ +#include "accel.hpp" + +#include "kd.hpp" +#include "kdslow.hpp" + +#include "../definitions/ray.hpp" +#include "../definitions/primatives/triangle.hpp" + +// enum AccelerationMode { +// MODE_ACCELERATION_DEFAULT, +// MODE_NONE, +// MODE_KD, +// MODE_KD_SLOW, +// MODE_BVH +// }; + +Acceleration::Acceleration(AccelerationMode mode) { + m_mode = mode; +} + +void Acceleration::Construct(std::vector triangles) { + switch (m_mode) { + case MODE_ACCELERATION_DEFAULT: + case MODE_NONE: + Constructed = false; + break; + + case MODE_KD: + m_bbox = new BBox; + m_bbox->MakeEmpty(); + + for (auto& triangle: triangles) { + for (int i = 0; i > 3; i++) { + m_bbox->Add(triangle->points[i]); + } + } + + m_kdtree = new KDTree; + BuildKDTree(m_kdtree, *m_bbox, triangles, 0); + + Constructed = true; + break; + + case MODE_KD_SLOW: + BuildKDTreeSlow(m_kdtreeslow, triangles); + Constructed = true; + break; + + default: + Constructed = false; + break; + } +} + +bool Acceleration::Intersect(Ray ray, Triangle*& triMin, float& tMin) { + if (!Constructed) return false; + switch (m_mode) { + case MODE_ACCELERATION_DEFAULT: + case MODE_NONE: + break; + + case MODE_KD: + return KDIntersect(m_kdtree, *m_bbox, ray, triMin, tMin); + break; + + case MODE_KD_SLOW: + return KDIntersectSlow(m_kdtreeslow, &ray, triMin, tMin); + break; + + default: + break; + } + return false; +} diff --git a/src/acceleration/accel.hpp b/src/acceleration/accel.hpp index 47bb8ef..fe637c0 100644 --- a/src/acceleration/accel.hpp +++ b/src/acceleration/accel.hpp @@ -1,9 +1,35 @@ #ifndef INFERNO_ACCELERATION_ACCEL_H_ #define INFERNO_ACCELERATION_ACCEL_H_ -class Acceleration { +#include "../common.hpp" +#include "bbox.hpp" + +#include + +class KDTree; +class KDTreeSlow; + +class Ray; +class Triangle; + +class Acceleration { +public: + Acceleration(AccelerationMode mode = MODE_ACCELERATION_DEFAULT); + + void Construct(std::vector triangles); + bool Intersect(Ray ray, Triangle*& triMin, float& tMin); + + bool Constructed = false; +private: + AccelerationMode m_mode = MODE_ACCELERATION_DEFAULT; + + // KDTree + KDTree* m_kdtree = nullptr; + BBox* m_bbox = nullptr; + + // Slow KDTree + KDTreeSlow* m_kdtreeslow = nullptr; - // virtual void }; #endif diff --git a/src/acceleration/kd.cpp b/src/acceleration/kd.cpp index 2b60dc4..b188108 100644 --- a/src/acceleration/kd.cpp +++ b/src/acceleration/kd.cpp @@ -14,18 +14,18 @@ bool autoSmooth; int maxDepthSum; int numNodes; -void KDTreeNode::InitLeaf(const std::vector& triangles) { +void KDTree::InitLeaf(const std::vector& triangles) { axis = AXIS_NONE; this->triangles = new std::vector(triangles); } -void KDTreeNode::InitTreeNode(Axis axis, float splitPos) { +void KDTree::InitTreeNode(Axis axis, float splitPos) { this->axis = axis; this->splitPos = splitPos; - this->children = new KDTreeNode[2]; + this->children = new KDTree[2]; } -KDTreeNode::~KDTreeNode() { +KDTree::~KDTree() { if (axis == AXIS_NONE) delete triangles; else @@ -33,7 +33,7 @@ KDTreeNode::~KDTreeNode() { } -void BuildKDTree(KDTreeNode* node, BBox bbox, std::vector& triangleList, int depth) { +void BuildKDTree(KDTree* node, BBox bbox, std::vector& triangleList, int depth) { if (depth > MAX_TREE_DEPTH || int(triangleList.size()) < TRIANGLES_PER_LEAF) { maxDepthSum += depth; numNodes++; @@ -64,7 +64,7 @@ void BuildKDTree(KDTreeNode* node, BBox bbox, std::vector& triangleLi BuildKDTree(&node->children[1], bboxRight, trianglesRight, depth + 1); } -bool KDIntersect(KDTreeNode* node, BBox& bbox, Ray& ray, Triangle*& intersect, float& t) { +bool KDIntersect(KDTree* 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++) { @@ -86,8 +86,8 @@ if (node->axis == AXIS_NONE) { BBox& firstBB = childBBox[childOrder[0]]; BBox& secondBB = childBBox[childOrder[1]]; - KDTreeNode& firstChild = node->children[childOrder[0]]; - KDTreeNode& secondChild = node->children[childOrder[1]]; + KDTree& firstChild = node->children[childOrder[0]]; + KDTree& 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 ) diff --git a/src/acceleration/kd.hpp b/src/acceleration/kd.hpp index 2a9225f..21d2757 100644 --- a/src/acceleration/kd.hpp +++ b/src/acceleration/kd.hpp @@ -7,20 +7,21 @@ class Triangle; class BBox; class Ray; -struct KDTreeNode { +struct KDTree { Axis axis; // AXIS_NONE if this is a leaf node - float splitPos; + float splitPos; + union { std::vector* triangles; - KDTreeNode* children; + KDTree* children; }; void InitLeaf(const std::vector& triangles); void InitTreeNode(Axis axis, float splitPos); - ~KDTreeNode(); -}; + ~KDTree(); +}; -void BuildKDTree(KDTreeNode* node, BBox bbox, std::vector& triangleList, int depth); -bool KDIntersect(KDTreeNode* node, BBox& bbox, Ray& ray, Triangle*& intersect, float& t); +void BuildKDTree(KDTree* node, BBox bbox, std::vector& triangleList, int depth); +bool KDIntersect(KDTree* node, BBox& bbox, Ray& ray, Triangle*& intersect, float& t); #endif diff --git a/src/acceleration/kdslow.cpp b/src/acceleration/kdslow.cpp new file mode 100644 index 0000000..7ed9387 --- /dev/null +++ b/src/acceleration/kdslow.cpp @@ -0,0 +1,215 @@ +#include "kdslow.hpp" + +#include + +#include "../definitions/primatives/primative.hpp" +#include "../definitions/primatives/triangle.hpp" +#include "../definitions/ray.hpp" + +Box::Box() { + return; +} + +Box::Box(Triangle* object) { + min.x = std::numeric_limits::max(); + min.y = std::numeric_limits::max(); + min.z = std::numeric_limits::max(); + + max.x = std::numeric_limits::lowest(); + max.y = std::numeric_limits::lowest(); + max.z = std::numeric_limits::lowest(); + + ExtendTriangle(object); +} + +void Box::ExtendTriangle(Triangle* object) { + ExtendPoint(object->points[0]); + ExtendPoint(object->points[1]); + ExtendPoint(object->points[2]); +} + +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; +} + +void BuildKDTreeSlow(KDTreeSlow* node, const std::vector& triangles) { + node = new KDTreeSlow(); + + node->children = triangles; + + if (triangles.size() == 0) + return; + + if (triangles.size() == 1) { + node->bounds = Box(triangles[0]); + + node->child0 = new KDTreeSlow(); + node->child1 = new KDTreeSlow(); + + node->child0->children = std::vector(); + node->child1->children = std::vector(); + + return; + } + + 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 bucket0; + std::vector 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]); + } + } + } + + if (bucket0.size() == 0 && bucket1.size() > 0) { + bucket0 = bucket1; + } + + 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++; + } + } + } + + float threshold = 0.5f; + + if ((float)matches / float(bucket0.size()) < threshold && + (float)matches / float(bucket1.size()) < threshold) { + BuildKDTreeSlow(node->child0, bucket0); + BuildKDTreeSlow(node->child1, bucket1); + } else { + node->child0 = new KDTreeSlow(); + node->child1 = new KDTreeSlow(); + + node->child0->children = std::vector(); + node->child1->children = std::vector(); + } +} + +bool KDIntersectSlow(KDTreeSlow* 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 = KDIntersectSlow(kd_tree1->child0, ray, triangle_min, t_min); + bool b = KDIntersectSlow(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; + } + } + + return false; +} diff --git a/src/acceleration/kdslow.hpp b/src/acceleration/kdslow.hpp new file mode 100644 index 0000000..d9b8f0a --- /dev/null +++ b/src/acceleration/kdslow.hpp @@ -0,0 +1,37 @@ +#ifndef INFERNO_ACCELERATION_KDSLOW_H_ +#define INFERNO_ACCELERATION_KDSLOW_H_ + +#include "../maths.hpp" + +class Triangle; +class Ray; + +class Box { +public: + Box(); + Box(Triangle* object); + + void ExtendTriangle(Triangle* object); + void ExtendPoint(glm::vec3 p); + int LongestAxis(); + + bool Hit(Ray* ray); + + glm::vec3 min = {}; + glm::vec3 max = {}; +}; + +class KDTreeSlow { +public: + Box bounds; + + KDTreeSlow* child0 = nullptr; + KDTreeSlow* child1 = nullptr; + + std::vector children; +}; + +void BuildKDTreeSlow(KDTreeSlow* tree, const std::vector& triangles); +bool KDIntersectSlow(KDTreeSlow* tree, Ray* ray, Triangle*& triMin, float& tMin); + +#endif diff --git a/src/common.hpp b/src/common.hpp index c56a223..3528097 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -7,10 +7,18 @@ #include enum OperationMode { - MODE_DEFAULT, + MODE_OPERATION_DEFAULT, MODE_PROGRESSIVE_GUI, MODE_PROGRESSIVE_IMG, MODE_SAMPLES_IMG }; +enum AccelerationMode { + MODE_ACCELERATION_DEFAULT, + MODE_NONE, + MODE_KD, + MODE_KD_SLOW, + MODE_BVH +}; + #endif diff --git a/src/core/renderer.hpp b/src/core/renderer.hpp index 0184e0f..caa9197 100644 --- a/src/core/renderer.hpp +++ b/src/core/renderer.hpp @@ -28,7 +28,7 @@ public: private: int m_samples = -1; - OperationMode m_mode = MODE_DEFAULT; + OperationMode m_mode = MODE_OPERATION_DEFAULT; DisplayInterface* m_interface = nullptr; uint32_t* m_framebuffer = nullptr; diff --git a/src/definitions/primatives/mesh.cpp b/src/definitions/primatives/mesh.cpp index a4d7be9..44ad21b 100644 --- a/src/definitions/primatives/mesh.cpp +++ b/src/definitions/primatives/mesh.cpp @@ -2,40 +2,25 @@ #include -#include "../../acceleration/kd.hpp" +#include "../../acceleration/accel.hpp" #include "../ray.hpp" #include "triangle.hpp" -Mesh::Mesh(std::vector tris) - : bbox() { - bbox.MakeEmpty(); - - for (auto& triangle: tris) { - for (int i = 0; i > 3; i++) { - bbox.Add(triangle->points[i]); - } - } - - triangles = tris; +Mesh::Mesh(std::vector tris) { + Triangles = tris; } -void Mesh::Optimise() { - if (!optimised) { - free((void*)m_kdTree); +void Mesh::Optimise(AccelerationMode mode) { + m_accelerator = new Acceleration(mode); + m_accelerator->Construct(Triangles); + if (m_accelerator->Constructed) Optimised = true; +} + +bool Mesh::Intersect(Ray ray, Triangle*& intersect, float& t) { + if (!Optimised) { + return TraceRayMesh(ray, this, t, intersect); } - m_kdTree = new KDTreeNode; - BuildKDTree(m_kdTree, bbox, triangles, 0); - - optimised = true; -} - -bool Mesh::Intersect(Ray* ray, Triangle*& intersect, float& t) { - if (!optimised) { - bool hit = TraceRayMesh(*ray, this, t, intersect); - return hit; - } - - return KDIntersect(m_kdTree, bbox, *ray, intersect, t); + return m_accelerator->Intersect(ray, intersect, t); } diff --git a/src/definitions/primatives/mesh.hpp b/src/definitions/primatives/mesh.hpp index 4dc8f07..6b30888 100644 --- a/src/definitions/primatives/mesh.hpp +++ b/src/definitions/primatives/mesh.hpp @@ -3,8 +3,10 @@ #include +#include "../../common.hpp" #include "../../acceleration/bbox.hpp" +class Acceleration; class Triangle; class KDTreeNode; class Ray; @@ -13,14 +15,13 @@ class Mesh { public: Mesh(std::vector triangles); - void Optimise(); - bool Intersect(Ray* ray, Triangle*& intersect, float& t); + void Optimise(AccelerationMode mode = MODE_KD_SLOW); + bool Intersect(Ray ray, Triangle*& intersect, float& t); - bool optimised = false; - std::vector triangles; + bool Optimised = false; + std::vector Triangles; private: - KDTreeNode* m_kdTree = nullptr; - BBox bbox; + Acceleration* m_accelerator = nullptr; }; #endif diff --git a/src/definitions/ray.cpp b/src/definitions/ray.cpp index e4d3586..3a0fb08 100644 --- a/src/definitions/ray.cpp +++ b/src/definitions/ray.cpp @@ -30,7 +30,7 @@ bool TraceRayScene(Ray ray, Scene* scene, float& t, Primative*& hit) { for (auto& mesh : scene->meshs) { float distance = INFINITY; Triangle* triHit = nullptr; - if (mesh->Intersect(&ray, triHit, distance)) { + if (mesh->Intersect(ray, triHit, distance)) { if (distance < lastDistance) { hit = triHit; lastDistance = distance; @@ -47,7 +47,7 @@ bool TraceRayScene(Ray ray, Scene* scene, float& t, Primative*& hit) { bool TraceRayMesh(Ray ray, Mesh* scene, float& t, Triangle*& hit) { float lastDistance = INFINITY; - for (auto& object : scene->triangles) { + for (auto& object : scene->Triangles) { float distance = INFINITY; if (object->Intersect(ray, distance)) { if (distance < lastDistance) { diff --git a/test/main.cpp b/test/main.cpp index b4b6209..1136c2a 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -21,20 +21,20 @@ int main(int argc, char** argv) { // std::vector tris = LoadTrianglesBasic("/home/ben/programming/inferno/resources/dragon-normals.obj"); // for (const auto& object : tris) - // object->Translate({ 0.0f, -5.0f, -20.0f }); - // std::cout << "loaded" << std::endl; + // object->Translate({ 0.0f, -5.0f, -20.0f }); - std::vector tris = LoadTrianglesBasic("/home/ben/programming/inferno/resources/lucy-normals.obj"); + // std::vector tris = LoadTrianglesBasic("/home/ben/programming/inferno/resources/lucy-normals.obj"); + // for (const auto& object : tris) + // object->Translate({ 0.0f, -3.9f, -10.6f }); + + std::vector tris = LoadTrianglesBasic("/home/ben/programming/inferno/resources/cornell.obj"); for (const auto& object : tris) - object->Translate({ 0.0f, -3.9f, -10.6f }); - std::cout << "loaded" << std::endl; + object->Translate({ 0.0f, -0.9f, -3.0f }); Mesh* mesh = new Mesh(tris); mesh->Optimise(); - std::cout << "tree built" << std::endl; scene->meshs.push_back(mesh); - inferno.SetScene(scene); inferno.Ready();