BVH Cleanup / Changes.

Working on fixing issues with the BVH implementation.
Commiting a working changes version. Code has been cleaned up considerably.
A proper code review is nessacary in the near future.
main
Brett 2022-11-13 13:03:48 -05:00
parent 9e533a86f6
commit 7a09800c40
29 changed files with 275 additions and 262 deletions

View File

@ -2,42 +2,27 @@
374 3235 1668323538168825062 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_tables.cpp.o f6dab204e07e8dcf 374 3235 1668323538168825062 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_tables.cpp.o f6dab204e07e8dcf
2 2022 1668323499583713805 CMakeFiles/Step_3.dir/src/graphics/gl/gl.c.o 30ab06816e8637c1 2 2022 1668323499583713805 CMakeFiles/Step_3.dir/src/graphics/gl/gl.c.o 30ab06816e8637c1
4 3390 1668323512856096078 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_demo.cpp.o 7798aba97da63e31 4 3390 1668323512856096078 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_demo.cpp.o 7798aba97da63e31
3 2621 1668323537552807322 CMakeFiles/Step_3.dir/src/engine/world.cpp.o 6470df278966c4 2 1840 1668361409895046083 CMakeFiles/Step_3.dir/src/engine/world.cpp.o 6470df278966c4
2 1153 1668323498715688802 CMakeFiles/Step_3.dir/src/engine/util/debug.cpp.o d86a254d2bce8f74 1 1716 1668360835926339635 CMakeFiles/Step_3.dir/src/engine/util/debug.cpp.o d86a254d2bce8f74
2 8763 1668323543696984256 CMakeFiles/Step_3.dir/src/engine/image/image.cpp.o 1c68ba16e6b4d09b 1 7565 1668362431984323343 CMakeFiles/Step_3.dir/src/engine/image/image.cpp.o 1c68ba16e6b4d09b
2 871 1668323498431680622 CMakeFiles/Step_3.dir/src/graphics/debug_gui.cpp.o 9493619f74acd06a 2 1499 1668360835706333174 CMakeFiles/Step_3.dir/src/graphics/debug_gui.cpp.o 9493619f74acd06a
4 605 1668323535536749264 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_impl_x11.cpp.o d1e9a2fcb31e2ec8 4 605 1668323535536749264 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_impl_x11.cpp.o d1e9a2fcb31e2ec8
0 26 1668323688289146536 build.ninja ccb5de0c063412ab 0 26 1668358519550031316 build.ninja ccb5de0c063412ab
1 920 1668323498479682005 CMakeFiles/Step_3.dir/src/engine/globals.cpp.o 4ef77d2224f86511 1 1621 1668360835826336698 CMakeFiles/Step_3.dir/src/engine/globals.cpp.o 4ef77d2224f86511
2 1403 1668323536336772303 CMakeFiles/Step_3.dir/src/engine/math/colliders.cpp.o 39e9f435096d066b 1 1405 1668362425824144748 CMakeFiles/Step_3.dir/src/engine/math/colliders.cpp.o 39e9f435096d066b
3 2335 1668323537268799144 CMakeFiles/Step_3.dir/src/engine/util/models.cpp.o 164394d360c43072 2 1712 1668362494026122707 CMakeFiles/Step_3.dir/src/engine/util/models.cpp.o 164394d360c43072
3 6633 1668323516100189511 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui.cpp.o 55e7538fd27b47be 3 6633 1668323516100189511 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui.cpp.o 55e7538fd27b47be
8763 8835 1668323543768986328 Step_3 f055ce2b85635598 2268 2354 1668361410407060406 Step_3 f055ce2b85635598
4 521 1668323535452746847 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_impl_glfw.cpp.o 6aef9db88eb3d76d 4 521 1668323535452746847 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_impl_glfw.cpp.o 6aef9db88eb3d76d
2 2720 1668323537648810087 CMakeFiles/Step_3.dir/src/engine/raytracing.cpp.o 11f0e227e9fda9ca 2 2015 1668362494330131524 CMakeFiles/Step_3.dir/src/engine/raytracing.cpp.o 11f0e227e9fda9ca
605 1795 1668323536728783593 CMakeFiles/Step_3.dir/src/graphics/input.cpp.o 510001b0955ab019 1499 2524 1668360836734363373 CMakeFiles/Step_3.dir/src/graphics/input.cpp.o 510001b0955ab019
5 4715 1668323514180134213 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_draw.cpp.o f89fa3d7b779872a 5 4715 1668323514180134213 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_draw.cpp.o f89fa3d7b779872a
521 6249 1668323541180911801 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_widgets.cpp.o 84017388bc7af144 521 6249 1668323541180911801 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_widgets.cpp.o 84017388bc7af144
3 2248 1668323537180796610 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d 2 1830 1668362494146126186 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d
3 2124 1668323537056793038 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3 2 1624 1668362426044151124 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3
4 374 1668323535308742700 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_impl_opengl3.cpp.o 1b5f0fbe3cf8ce4e 4 374 1668323535308742700 CMakeFiles/Step_3.dir/src/graphics/imgui/imgui_impl_opengl3.cpp.o 1b5f0fbe3cf8ce4e
3 2080 1668323537012791771 CMakeFiles/Step_3.dir/src/graphics/gl/shader.cpp.o 2553d57dba16057b 2 1617 1668362426036150892 CMakeFiles/Step_3.dir/src/graphics/gl/shader.cpp.o 2553d57dba16057b
2 3101 1668323538032821145 CMakeFiles/Step_3.dir/src/engine/main.cpp.o 641dce3f86933e2e 1 2419 1668362494734143245 CMakeFiles/Step_3.dir/src/engine/main.cpp.o 641dce3f86933e2e
2 1369 1668323498931695025 CMakeFiles/Step_3.dir/src/engine/util/parser.cpp.o 1007c86c207ac940 2 2242 1668360836450355031 CMakeFiles/Step_3.dir/src/engine/util/parser.cpp.o 1007c86c207ac940
1 1102 1668324071584170088 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3 2 1579 1668362569316307713 CMakeFiles/Step_3.dir/src/engine/world.cpp.o 6470df278966c4
1 1373 1668324071856177907 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d 1579 1704 1668362569440311315 Step_3 f055ce2b85635598
1374 1444 1668324071924179862 Step_3 f055ce2b85635598
1 1083 1668324105033131597 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3
1083 1160 1668324105109133783 Step_3 f055ce2b85635598
1 1080 1668324205980033050 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3
1 1310 1668324206208039601 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d
1310 1378 1668324206276041556 Step_3 f055ce2b85635598
1 1298 1668324222400504969 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d
1298 1369 1668324222472507037 Step_3 f055ce2b85635598
1 1075 1668324349212149162 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3
1 1305 1668324349440155714 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d
1305 1374 1668324349508157669 Step_3 f055ce2b85635598
1 1177 1668326424977049673 CMakeFiles/Step_3.dir/src/graphics/gl/gl.cpp.o 330ad35a6abf06c3
1 1405 1668326425205056279 CMakeFiles/Step_3.dir/src/graphics/graphics.cpp.o ce988de97a5cb51d
1 1911 1668326425713070995 CMakeFiles/Step_3.dir/src/engine/main.cpp.o 641dce3f86933e2e
1912 2024 1668326425821074124 Step_3 f055ce2b85635598

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 KiB

Binary file not shown.

View File

@ -1,3 +1,3 @@
Start testing: Nov 13 03:00 EST Start testing: Nov 13 13:02 EST
---------------------------------------------------------- ----------------------------------------------------------
End testing: Nov 13 03:00 EST End testing: Nov 13 13:02 EST

View File

@ -9,7 +9,7 @@ Size=550,680
Collapsed=1 Collapsed=1
[Window][Debug Menu] [Window][Debug Menu]
Pos=28,35 Pos=26,34
Size=339,226 Size=339,226
Collapsed=0 Collapsed=0

View File

@ -10,19 +10,30 @@
#include "engine/types.h" #include "engine/types.h"
#include <utility> #include <utility>
#include <cassert>
// A currently pure header implementation of a BVH. TODO: make source file. // A currently pure header implementation of a BVH. TODO: make source file.
// this is also for testing and might not make it into the step 2. // this is also for testing and might not make it into the step 2.
namespace Raytracing { namespace Raytracing {
struct BVHObject {
Object* ptr = nullptr;
AABB aabb;
};
struct BVHPartitionedSpace {
std::vector<BVHObject> left;
std::vector<BVHObject> right;
};
struct BVHNode { struct BVHNode {
public: public:
std::vector<Object*> objs; std::vector<BVHObject> objs;
AABB aabb; AABB aabb;
BVHNode* left; BVHNode* left;
BVHNode* right; BVHNode* right;
BVHNode(std::vector<Object*> objs, AABB aabb, BVHNode* left, BVHNode* right): objs(std::move(objs)), aabb(std::move(aabb)), BVHNode(std::vector<BVHObject> objs, AABB aabb, BVHNode* left, BVHNode* right): objs(std::move(objs)), aabb(std::move(aabb)),
left(left), right(right) {} left(left), right(right) {}
~BVHNode() { ~BVHNode() {
delete (left); delete (left);
@ -35,42 +46,30 @@ namespace Raytracing {
const int MAX_TREE_DEPTH = 50; const int MAX_TREE_DEPTH = 50;
BVHNode* root = nullptr; BVHNode* root = nullptr;
void del() {
// delete copied objects
for (auto* obj : root->objs)
delete(obj);
delete (root);
}
// splits the objs in the vector based on the provided AABBs // splits the objs in the vector based on the provided AABBs
static std::pair<std::vector<Object*>, std::vector<Object*>> static BVHPartitionedSpace partition(const std::pair<AABB, AABB>& aabbs, const std::vector<BVHObject>& objs) {
partition(const std::pair<AABB, AABB>& aabbs, const std::vector<Object*>& objs) { BVHPartitionedSpace space;
std::vector<Object*> a1; for (const auto& obj: objs) {
std::vector<Object*> a2;
for (auto* obj: objs) {
// if this object doesn't have an AABB, we cannot use a BVH on it // if this object doesn't have an AABB, we cannot use a BVH on it
if (obj->getAABB().isEmpty()) { // If this ever fails we have a problem with the implementation.
throw std::runtime_error("Invalid AABB provided to the BVH! (Your implementation is flawed)"); assert(obj.aabb.isEmpty());
if (obj.aabb.intersects(aabbs.first)) {
space.left.push_back(obj);
} else if (obj.aabb.intersects(aabbs.second)) {
space.right.push_back(obj);
} }
if (obj->getAABB().intersects(aabbs.first)) {
a1.push_back(obj);
} else if (obj->getAABB().intersects(aabbs.second)) {
a2.push_back(obj);
}
//tlog << "OBJ: " << obj->getAABB() << " " << obj->getAABB().intersects(aabbs.first) << " " << obj->getAABB().intersects(aabbs.second) << " " << objs.size() << "\n";
} }
//tlog << "we split into two of sizes: " << a1.size() << " " << a2.size() << " orig size: " << (a1.size() + a2.size()) << "\n"; return space;
return {a1, a2};
} }
BVHNode* addObjectsRecur(const std::vector<Object*>& objects, unsigned long prevSize) { BVHNode* addObjectsRecur(const std::vector<BVHObject>& objects, unsigned long prevSize) {
//ilog << "size: " << objects.size() << "\n"; //ilog << "size: " << objects.size() << "\n";
// prevSize was required to solve some really weird bugs // prevSize was required to solve some really weird bugs
// which are a TODO: // which are a TODO:
if ((objects.size() <= 2 && !objects.empty()) || prevSize == objects.size()) { if ((objects.size() <= 2 && !objects.empty()) || prevSize == objects.size()) {
AABB local; AABB local;
for (const auto& obj: objects) for (const auto& obj: objects)
local = local.expand(obj->getAABB()); local = local.expand(obj.aabb);
return new BVHNode(objects, local, nullptr, nullptr); return new BVHNode(objects, local, nullptr, nullptr);
} else if (objects.empty()) // should never reach here!! } else if (objects.empty()) // should never reach here!!
return nullptr; return nullptr;
@ -81,26 +80,24 @@ namespace Raytracing {
AABB world; AABB world;
for (const auto& obj: objects) { for (const auto& obj: objects) {
//tlog << obj->getAABB(); //tlog << obj->getAABB();
world = world.expand(obj->getAABB()); world = world.expand(obj.aabb);
} }
//tlog << "\n"; //tlog << "\n";
// then split and partition the world // then split and partition the world
auto spltAABB = world.splitByLongestAxis(); auto splitAABBs = world.splitByLongestAxis();
//dlog << "We have " << world << " being split into: \n\t" << spltAABB.first << "\n\t" << spltAABB.second << "\n"; auto partitionedObjs = partition(splitAABBs, objects);
auto partitionedObjs = partition(spltAABB, objects);
BVHNode* left = nullptr; BVHNode* left = nullptr;
BVHNode* right = nullptr; BVHNode* right = nullptr;
// don't try to explore nodes which don't have anything in them. // don't try to explore nodes which don't have anything in them.
if (!partitionedObjs.first.empty()) if (!partitionedObjs.left.empty())
left = addObjectsRecur(partitionedObjs.first, objects.size()); left = addObjectsRecur(partitionedObjs.left, objects.size());
if (!partitionedObjs.second.empty()) if (!partitionedObjs.right.empty())
right = addObjectsRecur(partitionedObjs.second, objects.size()); right = addObjectsRecur(partitionedObjs.right, objects.size());
return new BVHNode(objects, world, left, right); return new BVHNode(objects, world, left, right);
} }
static std::vector<Object*> static std::vector<BVHObject> traverseFindRayIntersection(BVHNode* node, const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) {
traverseFindRayIntersection(BVHNode* node, const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) {
// check for intersections on both sides of the tree // check for intersections on both sides of the tree
if (node->left != nullptr) { if (node->left != nullptr) {
if (node->left->aabb.intersects(ray, min, max)) if (node->left->aabb.intersects(ray, min, max))
@ -125,30 +122,32 @@ namespace Raytracing {
void addObjects(const std::vector<Object*>& objects) { void addObjects(const std::vector<Object*>& objects) {
if (root != nullptr) if (root != nullptr)
del(); throw std::runtime_error("BVHTree already exists. What are you trying to do?");
// move all the object's aabb's into world position // move all the object's aabb's into world position
std::vector<Object*> objs; std::vector<BVHObject> objs;
for (auto* obj: objects) { for (auto* obj: objects) {
// we don't want to store all the AABBs which don't exist // we don't want to store all the AABBs which don't exist
// ie spheres // ie spheres
if (obj->getAABB().isEmpty()) { if (obj->getAABB().isEmpty()) {
//tlog << "Goodbye\n";
noAABBObjects.push_back(obj); noAABBObjects.push_back(obj);
continue; continue;
} }
Object* objCopy = obj->clone(); BVHObject bvhObject;
objCopy->setAABB(obj->getAABB().translate(obj->getPosition())); // returns a copy of the AABB object and assigns it in to the tree storage object
objs.push_back(objCopy); bvhObject.aabb = obj->getAABB().translate(obj->getPosition());
// which means we don't have to do memory management, since we are using the pointer without ownership or coping now.
bvhObject.ptr = obj;
objs.push_back(bvhObject);
} }
root = addObjectsRecur(objs, -1); root = addObjectsRecur(objs, -1);
} }
std::vector<Object*> rayIntersect(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) { std::vector<BVHObject> rayIntersect(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) {
return traverseFindRayIntersection(root, ray, min, max); return traverseFindRayIntersection(root, ray, min, max);
} }
~BVHTree() { ~BVHTree() {
del(); delete (root);
} }
}; };

View File

@ -14,11 +14,8 @@ namespace Raytracing {
protected: protected:
Vec4 min; Vec4 min;
Vec4 max; Vec4 max;
bool empty = false;
public: public:
AABB() { AABB(): min({0,0,0}), max({0,0,0}) {};
empty = true;
};
AABB(PRECISION_TYPE minX, PRECISION_TYPE minY, PRECISION_TYPE minZ, PRECISION_TYPE maxX, PRECISION_TYPE maxY, PRECISION_TYPE maxZ): AABB(PRECISION_TYPE minX, PRECISION_TYPE minY, PRECISION_TYPE minZ, PRECISION_TYPE maxX, PRECISION_TYPE maxY, PRECISION_TYPE maxZ):
min{minX, minY, minZ}, max{maxX, maxY, maxZ} { min{minX, minY, minZ}, max{maxX, maxY, maxZ} {
@ -100,7 +97,9 @@ namespace Raytracing {
[[nodiscard]] PRECISION_TYPE avgDistanceFromCenter() const; [[nodiscard]] PRECISION_TYPE avgDistanceFromCenter() const;
[[nodiscard]] inline bool isEmpty() const { return empty; } // Returns true if the min and max are equal, which tells us this AABB wasn't assigned
// or was properly created. Either way it isn't responsible to use the AABB in said case.
[[nodiscard]] inline bool isEmpty() const { return min == max; }
[[nodiscard]] Vec4 getMin() const { return min; } [[nodiscard]] Vec4 getMin() const { return min; }

View File

@ -392,6 +392,10 @@ namespace Raytracing {
return out << "Vec4{" << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << "} "; return out << "Vec4{" << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << "} ";
} }
inline bool operator==(const Vec4& left, const Vec4& right) {
return left.x() == right.x() && left.y() == right.y() && left.z() == right.z() && left.w() == right.w();
}
class Ray { class Ray {
private: private:
// the starting point for our ray // the starting point for our ray

View File

@ -25,6 +25,8 @@
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <random> #include <random>
#include <cstdlib>
#include <memory>
/** /**
* defines * defines
@ -47,33 +49,45 @@ const double EPSILON = 0.0000001;
/** /**
* classes * classes
*/ */
static inline double degreeeToRadian(double deg){ static inline double degreeeToRadian(double deg) {
return deg * PI/180.0; return deg * PI / 180.0;
} }
namespace Raytracing { namespace Raytracing {
class AlignedAllocator {
private:
public:
// not sure if this actually provides a performance benefit. Testing is inconclusive
template<typename T>
static T* allocateCacheAligned(int number = 1) {
void* allocatedSpace = aligned_alloc(64, sizeof(T) * number);
return new(allocatedSpace) T[number];
}
};
class Random { class Random {
private: private:
std::random_device rd; // obtain a random number from hardware std::random_device rd; // obtain a random number from hardware
std::mt19937 gen; std::mt19937 gen;
std::uniform_real_distribution<double> doubleDistr {0, 1}; std::uniform_real_distribution<double> doubleDistr{0, 1};
public: public:
Random(): gen(std::mt19937(long(rd.entropy() * 691 * 691))) {} Random(): gen(std::mt19937(long(rd.entropy() * 691 * 691))) {}
Random(double min, double max): gen(std::mt19937(long(rd.entropy() * 691 * 691))), doubleDistr{min, max} {} Random(double min, double max): gen(std::mt19937(long(rd.entropy() * 691 * 691))), doubleDistr{min, max} {}
double getDouble(){ double getDouble() {
return doubleDistr(gen); return doubleDistr(gen);
} }
}; };
class String { class String {
public: public:
static inline std::string toLowerCase(const std::string& s){ static inline std::string toLowerCase(const std::string& s) {
std::stringstream str; std::stringstream str;
std::for_each(s.begin(), s.end(), [&str](unsigned char ch) { std::for_each(s.begin(), s.end(), [&str](unsigned char ch) {
str << (char) std::tolower(ch); str << (char) std::tolower(ch);
}); });
return str.str(); return str.str();
} }
static inline std::string toUpperCase(const std::string& s){ static inline std::string toUpperCase(const std::string& s) {
std::stringstream str; std::stringstream str;
std::for_each(s.begin(), s.end(), [&str](unsigned char ch) { std::for_each(s.begin(), s.end(), [&str](unsigned char ch) {
str << (char) std::toupper(ch); str << (char) std::toupper(ch);
@ -82,7 +96,7 @@ namespace Raytracing {
} }
// taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c // taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
// extended to return a vector // extended to return a vector
static inline std::vector<std::string> split(std::string s, const std::string& delim){ static inline std::vector<std::string> split(std::string s, const std::string& delim) {
size_t pos = 0; size_t pos = 0;
std::vector<std::string> tokens; std::vector<std::string> tokens;
while ((pos = s.find(delim)) != std::string::npos) { while ((pos = s.find(delim)) != std::string::npos) {
@ -102,7 +116,7 @@ namespace Raytracing {
})); }));
return s; return s;
} }
// trim from end (in place) // trim from end (in place)
static inline std::string& rtrim(std::string& s) { static inline std::string& rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
@ -110,26 +124,26 @@ namespace Raytracing {
}).base(), s.end()); }).base(), s.end());
return s; return s;
} }
// trim from both ends (in place) // trim from both ends (in place)
static inline std::string& trim(std::string& s) { static inline std::string& trim(std::string& s) {
ltrim(s); ltrim(s);
rtrim(s); rtrim(s);
return s; return s;
} }
// trim from start (copying) // trim from start (copying)
static inline std::string ltrim_copy(std::string s) { static inline std::string ltrim_copy(std::string s) {
ltrim(s); ltrim(s);
return s; return s;
} }
// trim from end (copying) // trim from end (copying)
static inline std::string rtrim_copy(std::string s) { static inline std::string rtrim_copy(std::string s) {
rtrim(s); rtrim(s);
return s; return s;
} }
// trim from both ends (copying) // trim from both ends (copying)
static inline std::string trim_copy(std::string s) { static inline std::string trim_copy(std::string s) {
trim(s); trim(s);
@ -138,9 +152,9 @@ namespace Raytracing {
}; };
} }
static Raytracing::Random rnd {}; static Raytracing::Random rnd{};
static inline double getRandomDouble(){ static inline double getRandomDouble() {
return rnd.getDouble(); return rnd.getDouble();
} }

View File

@ -14,6 +14,7 @@
#include <utility> #include <utility>
namespace Raytracing { namespace Raytracing {
class SphereObject : public Object { class SphereObject : public Object {
@ -114,14 +115,15 @@ namespace Raytracing {
* saving on computation * saving on computation
*/ */
// TODO: the above todo has been done, now we need to test the performance advantage of the BVH // TODO: the above todo has been done, now we need to test the performance advantage of the BVH
BVHTree* bvhTree = nullptr; std::unique_ptr<BVHTree> bvhObjects;
std::unordered_map<std::string, Material*> materials; std::unordered_map<std::string, Material*> materials;
public: public:
World() = default; World() = default;
World(const World& world) = delete; World(const World& world) = delete;
World(const World&& world) = delete; World(const World&& world) = delete;
// call this after you've added all the objects to the world. (Called by the raycaster class) // Called by the raytracer class after all objects have been added to the world
// this allows us to generate a statically unchanging BVH for easy rendering
void generateBVH(); void generateBVH();
inline void add(Object* object) { objects.push_back(object); } inline void add(Object* object) { objects.push_back(object); }

View File

@ -12,24 +12,167 @@
#include <engine/image/image.h> #include <engine/image/image.h>
#include <config.h> #include <config.h>
#include <graphics/gl/shader.h> #include <graphics/gl/shader.h>
#ifndef USE_GLFW #ifndef USE_GLFW
#include <GLES3/gl32.h> #include <GLES3/gl32.h>
#include <GLES3/gl3.h> #include <GLES3/gl3.h>
#include <GL/gl.h> #include <GL/gl.h>
#include "graphics/gl/glext.h" #include "graphics/gl/glext.h"
extern PFNGLCREATEVERTEXARRAYSPROC glCreateVertexArrays; extern PFNGLCREATEVERTEXARRAYSPROC glCreateVertexArrays;
extern PFNGLCREATEBUFFERSPROC glCreateBuffers; extern PFNGLCREATEBUFFERSPROC glCreateBuffers;
extern PFNGLNAMEDBUFFERDATAPROC glNamedBufferData; extern PFNGLNAMEDBUFFERDATAPROC glNamedBufferData;
extern PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData; extern PFNGLNAMEDBUFFERSUBDATAPROC glNamedBufferSubData;
extern PFNGLENABLEVERTEXARRAYATTRIBPROC glEnableVertexArrayAttrib; extern PFNGLENABLEVERTEXARRAYATTRIBPROC glEnableVertexArrayAttrib;
extern PFNGLVERTEXARRAYATTRIBBINDINGPROC glVertexArrayAttribBinding; extern PFNGLVERTEXARRAYATTRIBBINDINGPROC glVertexArrayAttribBinding;
extern PFNGLVERTEXARRAYATTRIBFORMATPROC glVertexArrayAttribFormat; extern PFNGLVERTEXARRAYATTRIBFORMATPROC glVertexArrayAttribFormat;
#else #else
#include <graphics/gl/glad/gl.h> #include <graphics/gl/glad/gl.h>
#endif #endif
class Shapes {
public:
struct cubeVertexBuilder {
std::vector<float> cubeVerticesRaw = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
};
std::vector<float> cubeUVs = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f
};
static cubeVertexBuilder getCubeExtends(float xRadius, float yRadius, float zRadius) {
cubeVertexBuilder builder {};
builder.cubeVerticesRaw = {
-0.5f, -0.5f, -zRadius,
0.5f, -0.5f, -zRadius,
0.5f, 0.5f, -zRadius,
0.5f, 0.5f, -zRadius,
-0.5f, 0.5f, -zRadius,
-0.5f, -0.5f, -zRadius,
-0.5f, -0.5f, zRadius,
0.5f, -0.5f, zRadius,
0.5f, 0.5f, zRadius,
0.5f, 0.5f, zRadius,
-0.5f, 0.5f, zRadius,
-0.5f, -0.5f, zRadius,
-xRadius, 0.5f, 0.5f,
-xRadius, 0.5f, -0.5f,
-xRadius, -0.5f, -0.5f,
-xRadius, -0.5f, -0.5f,
-xRadius, -0.5f, 0.5f,
-xRadius, 0.5f, 0.5f,
xRadius, 0.5f, 0.5f,
xRadius, 0.5f, -0.5f,
xRadius, -0.5f, -0.5f,
xRadius, -0.5f, -0.5f,
xRadius, -0.5f, 0.5f,
xRadius, 0.5f, 0.5f,
-0.5f, -yRadius, -0.5f,
0.5f, -yRadius, -0.5f,
0.5f, -yRadius, 0.5f,
0.5f, -yRadius, 0.5f,
-0.5f, -yRadius, 0.5f,
-0.5f, -yRadius, -0.5f,
-0.5f, yRadius, -0.5f,
0.5f, yRadius, -0.5f,
0.5f, yRadius, 0.5f,
0.5f, yRadius, 0.5f,
-0.5f, yRadius, 0.5f,
-0.5f, yRadius, -0.5f,
};
return builder;
}
};
};
// since we are doing everything with raytracing // since we are doing everything with raytracing
// the purpose of these utility classes are purely for debug // the purpose of these utility classes are purely for debug
// such as drawing bounding boxes around a BVH // such as drawing bounding boxes around a BVH
@ -46,8 +189,8 @@ class Texture {
unsigned char* data; unsigned char* data;
public: public:
Texture(Texture &&) noexcept = delete; // Disable move constructor. Texture(Texture&&) noexcept = delete; // Disable move constructor.
Texture& operator=(Texture &&) noexcept = delete; // Disable Move Assignment Texture& operator=(Texture&&) noexcept = delete; // Disable Move Assignment
Texture(); Texture();
explicit Texture(const std::string& path); explicit Texture(const std::string& path);
explicit Texture(Raytracing::Image* image); explicit Texture(Raytracing::Image* image);
@ -66,7 +209,7 @@ class VAO {
// vertex data // vertex data
unsigned int storeData(int attrNumber, int coordSize, int stride, long offset, int length, const float* data); unsigned int storeData(int attrNumber, int coordSize, int stride, long offset, int length, const float* data);
// element data (indices) // element data (indices)
unsigned int storeData(int length, const unsigned int *data); unsigned int storeData(int length, const unsigned int* data);
// instance data // instance data
unsigned int createInstanceVBO(int count, int bytePerInstance); unsigned int createInstanceVBO(int count, int bytePerInstance);
// used much in the same way that store data sets an attribute where the data is expected // used much in the same way that store data sets an attribute where the data is expected
@ -78,10 +221,10 @@ class VAO {
VAO(const VAO& that); // Disable Copy Constructor VAO(const VAO& that); // Disable Copy Constructor
VAO& operator=(const VAO& that); // Disable Copy Assignment VAO& operator=(const VAO& that); // Disable Copy Assignment
public: public:
VAO(VAO &&) noexcept = delete; // Disable move constructor. VAO(VAO&&) noexcept = delete; // Disable move constructor.
VAO& operator=(VAO &&) noexcept = delete; // Disable Move Assignment VAO& operator=(VAO&&) noexcept = delete; // Disable Move Assignment
explicit VAO(const std::vector<Raytracing::Triangle> &triangles); explicit VAO(const std::vector<Raytracing::Triangle>& triangles);
VAO(const std::vector<float>& verts, const std::vector<float>& uvs, const std::vector<unsigned int>& indices); VAO(const std::vector<float>& verts, const std::vector<float>& uvs, const std::vector<unsigned int>& indices);
VAO(const std::vector<float>& verts, const std::vector<float>& uvs); VAO(const std::vector<float>& verts, const std::vector<float>& uvs);

View File

@ -5,11 +5,15 @@ in vec2 outUv;
in vec3 outNormal; in vec3 outNormal;
uniform sampler2D tex; uniform sampler2D tex;
uniform int useWhite;
const vec3 lightDir = vec3(1.0, 1.0, 1.0); const vec3 lightDir = vec3(1.0, 1.0, 1.0);
void main() { void main() {
vec4 textureColor = texture(tex, outUv); vec4 textureColor = texture(tex, outUv);
//FragColor = vec4(textureColor.rgb, 1.0f); //FragColor = vec4(textureColor.rgb, 1.0f);
FragColor = vec4(vec3(1.0, 0.0f, 0.0f) * dot(lightDir, outNormal), 1.0f); if (useWhite == 0)
FragColor = vec4(vec3(1.0, 0.0f, 0.0f) * dot(lightDir, outNormal), 1.0f);
else
FragColor = vec4(1.0);
} }

View File

@ -12,7 +12,7 @@ namespace Raytracing {
delete (p); delete (p);
for (const auto& p: materials) for (const auto& p: materials)
delete (p.second); delete (p.second);
//delete(bvhTree); //delete(bvhObjects);
} }
HitData SphereObject::checkIfHit(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) const { HitData SphereObject::checkIfHit(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) const {
@ -58,25 +58,25 @@ namespace Raytracing {
std::pair<HitData, Object*> World::checkIfHit(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) const { std::pair<HitData, Object*> World::checkIfHit(const Ray& ray, PRECISION_TYPE min, PRECISION_TYPE max) const {
// actually speeds up rendering by about 110,000ms (total across 16 threads) // actually speeds up rendering by about 110,000ms (total across 16 threads)
if (bvhTree != nullptr){ if (bvhObjects != nullptr){
auto hResult = HitData{false, Vec4(), Vec4(), max}; auto hResult = HitData{false, Vec4(), Vec4(), max};
Object* objPtr = nullptr; Object* objPtr = nullptr;
auto intersected = bvhTree->rayIntersect(ray, min, max); auto intersected = bvhObjects->rayIntersect(ray, min, max);
//dlog << "Intersections " << intersected.size() << " " << ray << "\n"; //dlog << "Intersections " << intersected.size() << " " << ray << "\n";
for (auto* ptr : intersected) { for (const auto& ptr : intersected) {
auto cResult = ptr->checkIfHit(ray, min, hResult.length); auto cResult = ptr.ptr->checkIfHit(ray, min, hResult.length);
if (cResult.hit) { if (cResult.hit) {
hResult = cResult; hResult = cResult;
objPtr = ptr; objPtr = ptr.ptr;
} }
} }
// after we check the BVH, we have to check for other missing objects // after we check the BVH, we have to check for other missing objects
// since stuff like spheres currently don't have AABB and AABB isn't a requirement // since stuff like spheres currently don't have AABB and AABB isn't a requirement
// for the object class (to be assigned) // for the object class (to be assigned)
for (auto* obj: bvhTree->noAABBObjects) { for (auto* obj: bvhObjects->noAABBObjects) {
// check up to the point of the last closest hit, // check up to the point of the last closest hit,
// will give the closest object's hit result // will give the closest object's hit result
auto cResult = obj->checkIfHit(ray, min, hResult.length); auto cResult = obj->checkIfHit(ray, min, hResult.length);
@ -105,7 +105,7 @@ namespace Raytracing {
} }
void World::generateBVH() { void World::generateBVH() {
bvhTree = new BVHTree(objects); bvhObjects = std::make_unique<BVHTree>(objects);
} }
ScatterResults DiffuseMaterial::scatter(const Ray& ray, const HitData& hitData) const { ScatterResults DiffuseMaterial::scatter(const Ray& ray, const HitData& hitData) const {

View File

@ -14,143 +14,6 @@ extern bool* haltRaytracing;
namespace Raytracing { namespace Raytracing {
struct cubeVertexBuilder {
std::vector<float> cubeVerticesRaw = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
};
static cubeVertexBuilder getCubeExtends(float xRadius, float yRadius, float zRadius) {
cubeVertexBuilder builder;
builder.cubeVerticesRaw = {
-0.5f, -0.5f, -zRadius,
0.5f, -0.5f, -zRadius,
0.5f, 0.5f, -zRadius,
0.5f, 0.5f, -zRadius,
-0.5f, 0.5f, -zRadius,
-0.5f, -0.5f, -zRadius,
-0.5f, -0.5f, zRadius,
0.5f, -0.5f, zRadius,
0.5f, 0.5f, zRadius,
0.5f, 0.5f, zRadius,
-0.5f, 0.5f, zRadius,
-0.5f, -0.5f, zRadius,
-xRadius, 0.5f, 0.5f,
-xRadius, 0.5f, -0.5f,
-xRadius, -0.5f, -0.5f,
-xRadius, -0.5f, -0.5f,
-xRadius, -0.5f, 0.5f,
-xRadius, 0.5f, 0.5f,
xRadius, 0.5f, 0.5f,
xRadius, 0.5f, -0.5f,
xRadius, -0.5f, -0.5f,
xRadius, -0.5f, -0.5f,
xRadius, -0.5f, 0.5f,
xRadius, 0.5f, 0.5f,
-0.5f, -yRadius, -0.5f,
0.5f, -yRadius, -0.5f,
0.5f, -yRadius, 0.5f,
0.5f, -yRadius, 0.5f,
-0.5f, -yRadius, 0.5f,
-0.5f, -yRadius, -0.5f,
-0.5f, yRadius, -0.5f,
0.5f, yRadius, -0.5f,
0.5f, yRadius, 0.5f,
0.5f, yRadius, 0.5f,
-0.5f, yRadius, 0.5f,
-0.5f, yRadius, -0.5f,
};
return builder;
}
};
std::vector<float> cubeUVs = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f
};
const std::vector<float> vertices = { const std::vector<float> vertices = {
1.0f, 1.0f, 0.0f, // top right 1.0f, 1.0f, 0.0f, // top right
1.0f, -1.0f, 0.0f, // bottom right 1.0f, -1.0f, 0.0f, // bottom right