COSC-3P93-Project/Step 3/include/engine/math/bvh.h

236 lines
8.0 KiB
C
Raw Normal View History

2022-10-20 11:30:15 -04:00
/*
* Created by Brett Terpstra 6920201 on 17/10/22.
* Copyright (c) 2022 Brett Terpstra. All Rights Reserved.
*/
#ifndef STEP_2_BVH_H
#define STEP_2_BVH_H
#include "engine/util/std.h"
#include "engine/types.h"
2022-11-17 00:37:33 -05:00
#include "engine/util/models.h"
#include <config.h>
#ifdef COMPILE_GUI
#include <graphics/gl/gl.h>
#include <graphics/imgui/imgui.h>
#endif
2022-10-20 11:30:15 -04:00
#include <utility>
namespace Raytracing {
2022-12-13 01:33:31 -05:00
#ifdef COMPILE_GUI
extern std::shared_ptr<VAO> aabbVAO;
extern int count;
extern int selected;
2022-12-13 01:33:31 -05:00
#endif
struct BVHObject {
Object* ptr = nullptr;
AABB aabb;
};
struct BVHPartitionedSpace {
2022-12-13 01:33:31 -05:00
// corresponds to the AABB pair used to generate the partitioned space
std::vector<BVHObject> left;
std::vector<BVHObject> right;
};
2022-11-16 17:34:17 -05:00
inline bool operator==(const BVHPartitionedSpace& left, const BVHPartitionedSpace& right) {
2022-12-13 01:33:31 -05:00
// sometimes the partition function creates spaces with the same objects, which leads to infinite recursion.
// We can check if the spaces are equal and change the strategy used to split the AABB.
// and if that fails we can use this to just end the recursion.
2022-11-16 17:34:17 -05:00
if (left.left.size() != right.left.size() || left.right.size() != right.right.size())
return false;
2022-11-17 00:37:33 -05:00
for (int i = 0; i < left.left.size(); i++) {
2022-11-16 17:34:17 -05:00
if (left.left[i].aabb != right.left[i].aabb)
return false;
}
2022-11-17 00:37:33 -05:00
for (int i = 0; i < left.right.size(); i++) {
2022-11-16 17:34:17 -05:00
if (left.right[i].aabb != right.right[i].aabb)
return false;
}
return true;
}
2022-10-20 11:30:15 -04:00
struct BVHNode {
public:
2022-11-15 16:23:37 -05:00
struct BVHHitData {
BVHNode* ptr{};
AABBHitData data{};
2022-11-15 16:23:37 -05:00
bool hit = false;
};
std::vector<BVHObject> objs;
2022-10-20 11:30:15 -04:00
AABB aabb;
BVHNode* left;
BVHNode* right;
// debug ints.
int index, hit = 0;
2022-12-13 01:33:31 -05:00
BVHNode(std::vector<BVHObject> objs, AABB aabb, BVHNode* left, BVHNode* right): objs(std::move(objs)), aabb(std::move(aabb)),
2022-11-23 11:55:40 -05:00
left(left), right(right) {
#ifdef COMPILE_GUI
index = count++;
#endif
}
2022-12-13 01:33:31 -05:00
2022-10-20 11:30:15 -04:00
~BVHNode() {
delete (left);
delete (right);
}
};
class BVHTree {
private:
BVHNode* root = nullptr;
2022-12-13 01:33:31 -05:00
/**
* partition the objects to each AABB based on if they intersect with or not. if intersects both left will be preferred.
*/
static BVHPartitionedSpace partition(const std::pair<AABB, AABB>& aabbs, const std::vector<BVHObject>& objs);
2022-12-13 01:33:31 -05:00
/**
* Internal function to add objects to the correct BVH node. Creates the entire tree structure recursively. DO NOT USE.
*/
2022-11-16 17:34:17 -05:00
BVHNode* addObjectsRecursively(const std::vector<BVHObject>& objects, const BVHPartitionedSpace& prevSpace);
2022-12-13 01:33:31 -05:00
/**
* adds all the objects provided to the BVH, skipping objects which don't have proper AABBs
*/
void addObjects(const std::vector<Object*>& objects);
2022-10-20 11:30:15 -04:00
public:
std::vector<Object*> noAABBObjects;
2022-12-13 01:33:31 -05:00
/**
* creates the BVH using the provided objects, which should come from the world.
* @param objectsInWorld objects from the world to create the BVH which
*/
2022-10-20 11:30:15 -04:00
explicit BVHTree(const std::vector<Object*>& objectsInWorld) {
addObjects(objectsInWorld);
2022-12-13 01:33:31 -05:00
#ifdef COMPILE_GUI
if (aabbVAO == nullptr) {
// create a basic cube for displaying the AABBs when debugging
auto aabbVertexData = Shapes::cubeVertexBuilder{};
aabbVAO = std::make_shared<VAO>(aabbVertexData.cubeVerticesRaw, aabbVertexData.cubeUVs);
2022-12-13 01:33:31 -05:00
}
#endif
2022-10-20 11:30:15 -04:00
}
2022-12-13 01:33:31 -05:00
/**
* @return the root node of the BVH tree
*/
BVHNode* getRoot() { return root; }
2022-10-20 11:30:15 -04:00
2022-12-13 01:33:31 -05:00
/**
* @param ray ray to check intersection with
* @param min min of the ray to check
* @param max max of the ray to check
* @return a list of objects which the ray might intersect with between min and max
*/
std::vector<BVHObject> rayAnyHitIntersect(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max);
2022-12-13 01:33:31 -05:00
2022-10-20 11:30:15 -04:00
~BVHTree() {
delete (root);
2022-10-20 11:30:15 -04:00
}
};
2022-12-13 01:33:31 -05:00
/**
* Everything below this line is unused due to inconsistencies in performance. Some parts of the code may contain references to this
* however the actual algorithm doesn't take into account BVHs at the object level.
*/
2022-11-17 00:37:33 -05:00
struct TriangleBVHObject {
Vec4 position;
std::shared_ptr<Triangle> tri;
2022-11-17 00:37:33 -05:00
AABB aabb;
};
struct TriangleBVHPartitionedSpace {
std::vector<TriangleBVHObject> left;
std::vector<TriangleBVHObject> right;
};
inline bool operator==(const TriangleBVHPartitionedSpace& left, const TriangleBVHPartitionedSpace& right) {
if (left.left.size() != right.left.size() || left.right.size() != right.right.size())
return false;
for (int i = 0; i < left.left.size(); i++) {
if (!(left.left[i].aabb == right.left[i].aabb))
return false;
}
for (int i = 0; i < left.right.size(); i++) {
if (!(left.right[i].aabb == right.right[i].aabb))
return false;
}
return true;
}
2022-11-17 00:37:33 -05:00
struct TriangleBVHNode {
struct BVHHitData {
TriangleBVHNode* ptr{};
AABBHitData data{};
bool hit = false;
};
std::vector<TriangleBVHObject> objs;
AABB aabb;
TriangleBVHNode* left;
TriangleBVHNode* right;
// debug ints.
int index, hit = 0;
2022-12-13 01:33:31 -05:00
BVHHitData firstHitRayIntersectTraversal(const Ray& r, PRECISION_TYPE min, PRECISION_TYPE max);
2022-12-13 01:33:31 -05:00
2022-11-17 00:37:33 -05:00
TriangleBVHNode(std::vector<TriangleBVHObject> objs, AABB aabb, TriangleBVHNode* left, TriangleBVHNode* right)
2022-11-23 11:55:40 -05:00
: objs(std::move(objs)), aabb(std::move(aabb)), left(left), right(right) {
#ifdef COMPILE_GUI
index = count++;
#endif
}
2022-12-13 01:33:31 -05:00
2022-11-17 00:37:33 -05:00
~TriangleBVHNode() {
delete (left);
delete (right);
}
};
class TriangleBVHTree {
private:
TriangleBVHNode* root = nullptr;
static TriangleBVHPartitionedSpace partition(const std::pair<AABB, AABB>& aabbs, const std::vector<TriangleBVHObject>& objs);
2022-12-13 01:33:31 -05:00
TriangleBVHNode* addObjectsRecursively(const std::vector<TriangleBVHObject>& objects, const TriangleBVHPartitionedSpace& prevSpace);
2022-12-13 01:33:31 -05:00
public:
int index;
2022-12-13 01:33:31 -05:00
explicit TriangleBVHTree(const std::vector<TriangleBVHObject>& objectsInWorld) {
addObjects(objectsInWorld);
2022-12-13 01:33:31 -05:00
#ifdef COMPILE_GUI
auto aabbVertexData = Shapes::cubeVertexBuilder{};
if (aabbVAO == nullptr)
aabbVAO = std::make_shared<VAO>(aabbVertexData.cubeVerticesRaw, aabbVertexData.cubeUVs);
index = count++;
2022-12-13 01:33:31 -05:00
#endif
}
void addObjects(const std::vector<TriangleBVHObject>& objects);
2022-12-13 01:33:31 -05:00
TriangleBVHNode* getRoot() { return root; }
std::vector<TriangleBVHObject> rayFirstHitIntersect(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max);
2022-12-13 01:33:31 -05:00
std::vector<TriangleBVHObject> rayAnyHitIntersect(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max);
2022-12-13 01:33:31 -05:00
~TriangleBVHTree() {
delete (root);
}
};
2022-10-20 11:30:15 -04:00
}
#endif //STEP_2_BVH_H