diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e09a03..7cecc86 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,52 @@ { "files.associations": { - "chrono": "cpp" + "chrono": "cpp", + "array": "cpp", + "hash_map": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "thread": "cpp", + "type_traits": "cpp", + "tuple": "cpp", + "typeinfo": "cpp", + "utility": "cpp" } } \ No newline at end of file diff --git a/src/acceleration/kd.cpp b/src/acceleration/kd.cpp index 23993d5..d6b1cdc 100644 --- a/src/acceleration/kd.cpp +++ b/src/acceleration/kd.cpp @@ -1,3 +1,219 @@ #include "kd.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; +} + +KDTree* BuildKDTree(const std::vector& triangles) +{ + KDTree* node = new KDTree(); + + node->children = triangles; + + if (triangles.size() == 0) { + return node; + } + + if (triangles.size() == 1) { + node->bounds = Box(triangles[0]); + + node->child0 = new KDTree(); + node->child1 = new KDTree(); + + node->child0->children = std::vector(); + node->child1->children = std::vector(); + + 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 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) { + node->child0 = BuildKDTree(bucket0); + node->child1 = BuildKDTree(bucket1); + } else { + node->child0 = new KDTree(); + node->child1 = new KDTree(); + + node->child0->children = std::vector(); + node->child1->children = std::vector(); + } + + 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; + } + } + + return false; +} diff --git a/src/acceleration/kd.hpp b/src/acceleration/kd.hpp index 2aef6af..9e5fab6 100644 --- a/src/acceleration/kd.hpp +++ b/src/acceleration/kd.hpp @@ -33,6 +33,6 @@ public: KDTree* BuildKDTree(const std::vector& triangles); -bool KDIntersect(KDTree* tree, Ray* ray, Triangle*& triMin, float& uMin, float& vMin, float& tMin); +bool KDIntersect(KDTree* tree, Ray* ray, Triangle*& triMin, float& tMin); #endif diff --git a/src/definitions/primatives/mesh.cpp b/src/definitions/primatives/mesh.cpp index ff240aa..2f1356b 100644 --- a/src/definitions/primatives/mesh.cpp +++ b/src/definitions/primatives/mesh.cpp @@ -1,3 +1,30 @@ #include "mesh.hpp" +#include +#include "../../acceleration/kd.hpp" +#include "../ray.hpp" + +#include "triangle.hpp" + +Mesh::Mesh(std::vector tris) { + triangles = tris; +} + +void Mesh::Optimise() { + if (!optimised) { + free((void*)m_kdTree); + } + + m_kdTree = BuildKDTree(triangles); + 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, ray, intersect, t); +} diff --git a/src/definitions/primatives/mesh.hpp b/src/definitions/primatives/mesh.hpp index 58343b7..263f39c 100644 --- a/src/definitions/primatives/mesh.hpp +++ b/src/definitions/primatives/mesh.hpp @@ -4,9 +4,20 @@ #include class Triangle; +class KDTree; +class Ray; class Mesh { +public: + Mesh(std::vector triangles); + + void Optimise(); + bool Intersect(Ray* ray, Triangle*& intersect, float& t); + + bool optimised = false; std::vector triangles; +private: + KDTree* m_kdTree = nullptr; }; #endif diff --git a/src/definitions/primatives/plane.cpp b/src/definitions/primatives/plane.cpp index dea6c03..07b061a 100644 --- a/src/definitions/primatives/plane.cpp +++ b/src/definitions/primatives/plane.cpp @@ -1,7 +1,7 @@ #include "plane.hpp" #include "../ray.hpp" -bool Plane::DoesIntersect(Ray& ray, float& t) { +bool Plane::Intersect(Ray& ray, float& t) { t = INFINITY; float dNormal = glm::dot(normal, ray.direction); if (dNormal > 1e-6) { diff --git a/src/definitions/primatives/plane.hpp b/src/definitions/primatives/plane.hpp index 6bc6613..eba11cb 100644 --- a/src/definitions/primatives/plane.hpp +++ b/src/definitions/primatives/plane.hpp @@ -8,7 +8,7 @@ public: Plane(glm::vec3 center, glm::vec3 normal) : Primative(center, normal) { } - bool DoesIntersect(Ray& ray, float& t) override; + bool Intersect(Ray& ray, float& t) override; glm::vec3 SurfaceNormal(glm::vec3 hitPoint) override; glm::vec2 TexCoords(glm::vec3 hitPoint) override; void Translate(glm::vec3 trans) override; diff --git a/src/definitions/primatives/primative.hpp b/src/definitions/primatives/primative.hpp index 49586e9..03d3f36 100644 --- a/src/definitions/primatives/primative.hpp +++ b/src/definitions/primatives/primative.hpp @@ -46,7 +46,7 @@ public: type = TYPE_TRI; } - virtual bool DoesIntersect(Ray& ray, float& t) = 0; + virtual bool Intersect(Ray& ray, float& t) = 0; virtual glm::vec3 SurfaceNormal(glm::vec3 hitPoint) = 0; virtual glm::vec2 TexCoords(glm::vec3 hitPoint) = 0; virtual void Translate(glm::vec3 trans) = 0; diff --git a/src/definitions/primatives/sphere.cpp b/src/definitions/primatives/sphere.cpp index ef489f4..138e520 100644 --- a/src/definitions/primatives/sphere.cpp +++ b/src/definitions/primatives/sphere.cpp @@ -1,7 +1,7 @@ #include "../ray.hpp" #include "sphere.hpp" -bool Sphere::DoesIntersect(Ray& ray, float& t) { +bool Sphere::Intersect(Ray& ray, float& t) { float t0, t1; // Solutions for intersect glm::vec3 l = center - ray.origin; diff --git a/src/definitions/primatives/sphere.hpp b/src/definitions/primatives/sphere.hpp index 67f8b47..ac2c7b5 100644 --- a/src/definitions/primatives/sphere.hpp +++ b/src/definitions/primatives/sphere.hpp @@ -8,7 +8,7 @@ public: Sphere(glm::vec3 center, float radius) : Primative(center, radius) { } - bool DoesIntersect(Ray& ray, float& t) override; + bool Intersect(Ray& ray, float& t) override; glm::vec3 SurfaceNormal(glm::vec3 hitPoint) override; glm::vec2 TexCoords(glm::vec3 hitPoint) override; void Translate(glm::vec3 trans) override; diff --git a/src/definitions/primatives/triangle.cpp b/src/definitions/primatives/triangle.cpp index 4005f1f..9c30341 100644 --- a/src/definitions/primatives/triangle.cpp +++ b/src/definitions/primatives/triangle.cpp @@ -1,7 +1,7 @@ #include "triangle.hpp" #include "../ray.hpp" -bool Triangle::DoesIntersect(Ray& ray, float& t) { +bool Triangle::Intersect(Ray& ray, float& t) { glm::vec3 vertex0 = points[0]; glm::vec3 vertex1 = points[1]; glm::vec3 vertex2 = points[2]; @@ -43,3 +43,7 @@ void Triangle::Translate(glm::vec3 trans) { points[1] += trans; points[2] += trans; } + +glm::vec3 Triangle::Midpoint() { + return (points[0] + points[1] + points[2]) / 3.0f; +} diff --git a/src/definitions/primatives/triangle.hpp b/src/definitions/primatives/triangle.hpp index 0add235..7e39fec 100644 --- a/src/definitions/primatives/triangle.hpp +++ b/src/definitions/primatives/triangle.hpp @@ -8,11 +8,11 @@ public: Triangle(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2, glm::vec3 n0, glm::vec3 n1, glm::vec3 n2) : Primative(p0, p1, p2, n0, n1, n2) { } - bool DoesIntersect(Ray& ray, float& t) override; + bool Intersect(Ray& ray, float& t) override; glm::vec3 SurfaceNormal(glm::vec3 hitPoint) override; glm::vec2 TexCoords(glm::vec3 hitPoint) override; void Translate(glm::vec3 trans) override; - glm::vec3 Midpoint(Triangle* t); + glm::vec3 Midpoint(); }; #endif diff --git a/src/definitions/ray.cpp b/src/definitions/ray.cpp index d1f29ae..cca491d 100644 --- a/src/definitions/ray.cpp +++ b/src/definitions/ray.cpp @@ -1,27 +1,75 @@ #include "ray.hpp" #include "scene.hpp" -#include "primatives/primative.hpp" -bool TraceRay(Ray ray, Scene* scene, float& t, Primative*& hit) { +#include + +#include "primatives/primative.hpp" +#include "primatives/triangle.hpp" +#include "primatives/mesh.hpp" + +bool TraceRayScene(Ray ray, Scene* scene, float& t, Primative*& hit) { int i = 0; float lastDistance = INFINITY; - int index = -1; + for (auto& object : scene->objects) { float distance = INFINITY; - if (object->DoesIntersect(ray, distance)) { + if (object->Intersect(ray, distance)) { if (distance < lastDistance) { - index = i; + hit = object; + lastDistance = distance; + } + } + } + + for (auto& mesh : scene->meshs) { + float distance = INFINITY; + Triangle* triHit = nullptr; + if (mesh->Intersect(&ray, triHit, distance)) { + if (distance < lastDistance) { + hit = triHit; lastDistance = distance; } } - i++; } t = lastDistance; - - if (index == -1) return false; - - hit = scene->objects[index]; + if (lastDistance == INFINITY || hit == nullptr) return false; return true; } + +bool TraceRayMesh(Ray ray, Mesh* scene, float& t, Triangle*& hit) { + float lastDistance = INFINITY; + + for (auto& object : scene->triangles) { + float distance = INFINITY; + if (object->Intersect(ray, distance)) { + if (distance < lastDistance) { + hit = object; + lastDistance = distance; + } + } + } + + t = lastDistance; + if (lastDistance == INFINITY || hit == nullptr) return false; + return true; +} + +bool TraceRayTriangles(Ray ray, std::vector scene, float& t, Triangle*& hit) { + float lastDistance = INFINITY; + + for (auto& object : scene) { + float distance = INFINITY; + if (object->Intersect(ray, distance)) { + if (distance < lastDistance) { + hit = object; + lastDistance = distance; + } + } + } + + t = lastDistance; + if (lastDistance == INFINITY || hit == nullptr) return false; + return true; +} diff --git a/src/definitions/ray.hpp b/src/definitions/ray.hpp index ce8d4f2..5e15f93 100644 --- a/src/definitions/ray.hpp +++ b/src/definitions/ray.hpp @@ -1,9 +1,12 @@ #ifndef INFERNO_DEFINITIONS_RAY_H_ #define INFERNO_DEFINITIONS_RAY_H_ +#include #include "../maths.hpp" +class Mesh; class Scene; +class Triangle; class Primative; class Ray { @@ -12,6 +15,8 @@ public: glm::vec3 direction = {}; }; -bool TraceRay(Ray ray, Scene* scene, float& t, Primative*& hit); +bool TraceRayScene(Ray ray, Scene* scene, float& t, Primative*& hit); +bool TraceRayMesh(Ray ray, Mesh* scene, float& t, Triangle*& hit); +bool TraceRayTriangles(Ray ray, std::vector scene, float& t, Triangle*& hit); #endif diff --git a/src/engine/progressiverenderer.cpp b/src/engine/progressiverenderer.cpp index 621e746..256c51e 100644 --- a/src/engine/progressiverenderer.cpp +++ b/src/engine/progressiverenderer.cpp @@ -10,7 +10,6 @@ #include "../util/assetloader.hpp" #include "../definitions/primatives/primative.hpp" -#include "../definitions/primatives/triangle.hpp" #include "../definitions/camera.hpp" #include "../definitions/scene.hpp" #include "../definitions/ray.hpp" @@ -25,10 +24,6 @@ void ProgressiveRenderer::Init(DisplayInterface* interface, Scene* scene) { } void ProgressiveRenderer::Render() { - m_scene->objects = LoadTrianglesBasic("/home/ben/programming/inferno/resources/cornell.obj"); - for (const auto& object : m_scene->objects) - object->Translate({ 0.0f, -1.0f, -3.0f }); - int frames = 0; auto startTime = std::chrono::high_resolution_clock::now(); @@ -49,7 +44,7 @@ void ProgressiveRenderer::Render() { float t; Primative* hit = nullptr; - bool didhit = TraceRay(ray, m_scene, t, hit); + bool didhit = TraceRayScene(ray, m_scene, t, hit); if (!didhit) { m_interface->SetPixelSafe(x, y, 0x000000); continue; diff --git a/src/inferno.hpp b/src/inferno.hpp index d56a877..b04dc78 100644 --- a/src/inferno.hpp +++ b/src/inferno.hpp @@ -8,8 +8,11 @@ #include "common.hpp" // Give the user access to the base classes to define shit +#include "util/assetloader.hpp" + #include "definitions/scene.hpp" #include "definitions/camera.hpp" +#include "definitions/primatives/mesh.hpp" #include "definitions/primatives/sphere.hpp" #include "definitions/primatives/plane.hpp" #include "definitions/primatives/triangle.hpp" diff --git a/src/util/assetloader.cpp b/src/util/assetloader.cpp index b484992..7711390 100644 --- a/src/util/assetloader.cpp +++ b/src/util/assetloader.cpp @@ -19,7 +19,7 @@ glm::vec3 getNormal(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) { return normal; } -std::vector LoadTrianglesBasic(std::string path) { +std::vector LoadTrianglesBasic(std::string path) { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; @@ -90,11 +90,5 @@ std::vector LoadTrianglesBasic(std::string path) { } } - std::vector objects; - - for (const auto& triangle : triangles) - objects.push_back(triangle); - - return objects; + return triangles; } - diff --git a/src/util/assetloader.hpp b/src/util/assetloader.hpp index 365de30..170c2ea 100644 --- a/src/util/assetloader.hpp +++ b/src/util/assetloader.hpp @@ -6,8 +6,8 @@ #include #include -class Primative; +class Triangle; -std::vector LoadTrianglesBasic(std::string path); +std::vector LoadTrianglesBasic(std::string path); #endif diff --git a/test/main.cpp b/test/main.cpp index bbe27ee..f5b7d00 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -16,8 +16,15 @@ int main(int argc, char** argv) { Scene* scene = new Scene(width, height); scene->camera = new Camera(width, height); - scene->objects.push_back(new Plane({0.0f, -0.5f, 0.0f}, {0.0f, -1.0f, 0.0f})); scene->objects.push_back(new Sphere({0.0f, 0.0f, -4.0f}, 1.0f)); + std::vector tris = LoadTrianglesBasic("/home/ben/programming/inferno/resources/cornell.obj"); + for (const auto& object : tris) + object->Translate({ 0.0f, -1.0f, -3.0f }); + + Mesh* mesh = new Mesh(tris); + mesh->Optimise(); + scene->meshs.push_back(mesh); + inferno.SetScene(scene);