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
|
@ -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
|
|
||||||
|
|
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 573 KiB |
After Width: | Height: | Size: 597 KiB |
After Width: | Height: | Size: 602 KiB |
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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";
|
return space;
|
||||||
}
|
|
||||||
//tlog << "we split into two of sizes: " << a1.size() << " " << a2.size() << " orig size: " << (a1.size() + a2.size()) << "\n";
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* defines
|
* defines
|
||||||
|
@ -52,6 +54,17 @@ static inline double degreeeToRadian(double deg){
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -64,6 +77,7 @@ namespace Raytracing {
|
||||||
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) {
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#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>
|
||||||
|
@ -27,9 +28,151 @@
|
||||||
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
|
||||||
|
|
|
@ -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);
|
||||||
|
if (useWhite == 0)
|
||||||
FragColor = vec4(vec3(1.0, 0.0f, 0.0f) * dot(lightDir, outNormal), 1.0f);
|
FragColor = vec4(vec3(1.0, 0.0f, 0.0f) * dot(lightDir, outNormal), 1.0f);
|
||||||
|
else
|
||||||
|
FragColor = vec4(1.0);
|
||||||
}
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|