Working on OctTree tests
This commit is contained in:
+28
-21
@@ -7,17 +7,17 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
//To be able to sort nodes based on distance to ray origin.
|
||||
struct ChildInfo
|
||||
{
|
||||
int Index;
|
||||
float Distance;
|
||||
};
|
||||
//To be able to sort nodes based on distance to ray origin.
|
||||
struct ChildInfo
|
||||
{
|
||||
int Index;
|
||||
float Distance;
|
||||
};
|
||||
|
||||
bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
|
||||
{
|
||||
return first.Distance < second.Distance;
|
||||
}
|
||||
bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
|
||||
{
|
||||
return first.Distance < second.Distance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,28 +32,31 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
|
||||
for (OctTree*& c : m_Children) {
|
||||
c = nullptr;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
--subDivisions;
|
||||
const glm::vec3& parentMin = m_Box.MinCorner();
|
||||
const glm::vec3& parentMax = m_Box.MaxCorner();
|
||||
const glm::vec3& parentCenter = m_Box.Center();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
glm::vec3 minPos, maxPos;
|
||||
const glm::vec3& parentMin = m_Box.MinCorner();
|
||||
const glm::vec3& parentMax = m_Box.MaxCorner();
|
||||
const glm::vec3& parentCenter = m_Box.Center();
|
||||
std::bitset<3> bits(i);
|
||||
//If child is 4,5,6,7.
|
||||
if (bits.test(2)) {
|
||||
minPos.x = parentCenter.x;
|
||||
maxPos.x = parentMax.x;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
minPos.x = parentMin.x;
|
||||
maxPos.x = parentCenter.x;
|
||||
}
|
||||
|
||||
|
||||
//If child is 2,3,6,7
|
||||
if (bits.test(1)) {
|
||||
minPos.y = parentCenter.y;
|
||||
maxPos.y = parentMax.y;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
minPos.y = parentMin.y;
|
||||
maxPos.y = parentCenter.y;
|
||||
}
|
||||
@@ -61,7 +64,8 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
|
||||
if (bits.test(0)) {
|
||||
minPos.z = parentCenter.z;
|
||||
maxPos.z = parentMax.z;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
minPos.z = parentMin.z;
|
||||
maxPos.z = parentCenter.z;
|
||||
}
|
||||
@@ -107,7 +111,8 @@ bool OctTree::rayCollides(const Ray& ray, Output& data) const
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//Check against boxes in the node.
|
||||
float minDist = INFINITY;
|
||||
bool intersected = false;
|
||||
@@ -162,7 +167,8 @@ void OctTree::AddBox(const AABB& box)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
m_ContainingBoxes.push_back(box);
|
||||
}
|
||||
}
|
||||
@@ -175,7 +181,8 @@ void OctTree::ClearBoxes()
|
||||
for (OctTree*& c : m_Children) {
|
||||
c->ClearBoxes();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
m_ContainingBoxes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using boost::unit_test_framework::test_suite;
|
||||
using boost::unit_test_framework::test_case;
|
||||
#include <stdlib.h>//srand
|
||||
#include "OctTreeTestGameClass.h"
|
||||
//HACK! Needed for white box testing
|
||||
//else we would have to "open up" the octTree class more with get/sets, public methods, etc. which is not good encapsulation-wise
|
||||
//friend class and refactoringIntoNewClass is some extra work and needs to be updated when the original class is updated, and can contain bugs that
|
||||
@@ -10,7 +11,6 @@ using boost::unit_test_framework::test_case;
|
||||
//http://stackoverflow.com/questions/6778496/how-to-do-unit-testing-on-private-members-and-methods-of-c-classes
|
||||
//http://stackoverflow.com/questions/3676664/unit-testing-of-private-methods
|
||||
#define private public
|
||||
|
||||
#include <Engine\Core\OctTree.h>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(octTreeTests)
|
||||
@@ -55,6 +55,10 @@ BOOST_AUTO_TEST_CASE(octTreeTest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(octTreeTest2)
|
||||
{
|
||||
Game game(0, nullptr);
|
||||
while (game.Running()) {
|
||||
game.Tick();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "OctTreeTestGameClass.h"
|
||||
|
||||
Game::Game(int argc, char* argv[])
|
||||
{
|
||||
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||
ResourceManager::RegisterType<Model>("Model");
|
||||
ResourceManager::RegisterType<Texture>("Texture");
|
||||
|
||||
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
|
||||
|
||||
// Create the core event broker
|
||||
m_EventBroker = new EventBroker();
|
||||
|
||||
m_RenderQueueFactory = new RenderQueueFactory();
|
||||
|
||||
// Create the renderer
|
||||
m_Renderer = new Renderer();
|
||||
m_Renderer->SetFullscreen(m_Config->Get<bool>("Video.Fullscreen", false));
|
||||
m_Renderer->SetVSYNC(m_Config->Get<bool>("Video.VSYNC", false));
|
||||
m_Renderer->SetResolution(Rectangle(
|
||||
0,
|
||||
0,
|
||||
m_Config->Get<int>("Video.Width", 1280),
|
||||
m_Config->Get<int>("Video.Height", 720)
|
||||
));
|
||||
m_Renderer->Initialize();
|
||||
|
||||
// Create input manager
|
||||
m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker);
|
||||
|
||||
// Create the root level GUI frame
|
||||
m_FrameStack = new GUI::Frame(m_EventBroker);
|
||||
m_FrameStack->Width = m_Renderer->Resolution().Width;
|
||||
m_FrameStack->Height = m_Renderer->Resolution().Height;
|
||||
|
||||
// Create a TEST WORLD
|
||||
m_World = new HardcodedTestWorld();
|
||||
|
||||
m_LastTime = glfwGetTime();
|
||||
}
|
||||
|
||||
Game::~Game()
|
||||
{
|
||||
delete m_FrameStack;
|
||||
delete m_EventBroker;
|
||||
}
|
||||
|
||||
void Game::Tick()
|
||||
{
|
||||
double currentTime = glfwGetTime();
|
||||
double dt = currentTime - m_LastTime;
|
||||
m_LastTime = currentTime;
|
||||
|
||||
m_EventBroker->Swap();
|
||||
m_InputManager->Update(dt);
|
||||
m_Renderer->Update(dt);
|
||||
m_EventBroker->Swap();
|
||||
|
||||
//movement
|
||||
//auto transf = m_World->GetComponent(m_World->OctTreeEntityIdSaved, "Transform");
|
||||
//((glm::vec3&)transf["Position"]).x += 0.001f;
|
||||
|
||||
m_RenderQueueFactory->Update(m_World);
|
||||
|
||||
//wireframe
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
|
||||
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
|
||||
m_EventBroker->Swap();
|
||||
m_EventBroker->Clear();
|
||||
|
||||
glfwPollEvents();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef Game_h__
|
||||
#define Game_h__
|
||||
|
||||
#include "Core/ResourceManager.h"
|
||||
#include "Core/ConfigFile.h"
|
||||
#include "Core/EventBroker.h"
|
||||
#include "Rendering/Renderer.h"
|
||||
#include "Core/InputManager.h"
|
||||
#include "GUI/Frame.h"
|
||||
#include "Core/World.h"
|
||||
#include "Rendering/RenderQueueFactory.h"
|
||||
|
||||
#include "OctTreeTestHardCodedTestWorld.h"
|
||||
|
||||
class Game
|
||||
{
|
||||
public:
|
||||
Game(int argc, char* argv[]);
|
||||
~Game();
|
||||
|
||||
bool Running() const { return !glfwWindowShouldClose(m_Renderer->Window()); }
|
||||
void Tick();
|
||||
|
||||
private:
|
||||
double m_LastTime;
|
||||
ConfigFile* m_Config = nullptr;
|
||||
EventBroker* m_EventBroker;
|
||||
IRenderer* m_Renderer;
|
||||
InputManager* m_InputManager;
|
||||
GUI::Frame* m_FrameStack;
|
||||
HardcodedTestWorld* m_World;
|
||||
RenderQueueFactory* m_RenderQueueFactory;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
//#define BOOST_TEST_MODULE collTest
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/execution_monitor.hpp>
|
||||
using boost::unit_test_framework::test_suite;
|
||||
using boost::unit_test_framework::test_case;
|
||||
#include <Engine\Core\Collision.h>
|
||||
#include "Engine/Core/AABB.h"
|
||||
#include "Engine/Core/Ray.h"
|
||||
#include <stdlib.h>//srand
|
||||
#include "Engine/Core/OctTree.h"
|
||||
|
||||
//vs memleaks
|
||||
//#define _CRTDBG_MAP_ALLOC
|
||||
//#include <stdlib.h>
|
||||
//#include <crtdbg.h>
|
||||
//#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
|
||||
//#define new DEBUG_CLIENTBLOCK
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(collisionTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(collisionTest)
|
||||
{
|
||||
//memleak
|
||||
int* globalLeak = new int[5];
|
||||
|
||||
//fixed seed
|
||||
srand(2);
|
||||
Ray ray;
|
||||
AABB someAABB;
|
||||
glm::vec3 minPos;
|
||||
glm::vec3 maxPos;
|
||||
bool z;
|
||||
int test = 0;
|
||||
for (size_t i = 0; i < 10; i++)
|
||||
{
|
||||
ray.Origin.x = rand() % 100;
|
||||
ray.Origin.y = rand() % 100;
|
||||
ray.Origin.z = rand() % 100;
|
||||
ray.Direction.x = rand() % 100;
|
||||
ray.Direction.y = rand() % 100;
|
||||
ray.Direction.z = rand() % 100;
|
||||
minPos.x = rand() % 100;
|
||||
minPos.y = rand() % 100;
|
||||
minPos.z = rand() % 100;
|
||||
maxPos.x = rand() % 100;
|
||||
maxPos.y = rand() % 100;
|
||||
maxPos.z = rand() % 100;
|
||||
|
||||
someAABB = AABB(minPos, maxPos);
|
||||
z = Collision::RayVsAABB(ray, someAABB);
|
||||
if (z) ++test;
|
||||
}
|
||||
BOOST_CHECK(test >= 0);
|
||||
|
||||
//_CrtDumpMemoryLeaks();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(collisionTest2)
|
||||
{
|
||||
//fixed seed
|
||||
srand(2);
|
||||
Ray ray;
|
||||
AABB someAABB;
|
||||
glm::vec3 minPos;
|
||||
glm::vec3 maxPos;
|
||||
bool z;
|
||||
int test = 0;
|
||||
for (size_t i = 0; i < 1000000; i++)
|
||||
{
|
||||
ray.Origin.x = rand() % 100;
|
||||
ray.Origin.y = rand() % 100;
|
||||
ray.Origin.z = rand() % 100;
|
||||
ray.Direction.x = rand() % 100;
|
||||
ray.Direction.y = rand() % 100;
|
||||
ray.Direction.z = rand() % 100;
|
||||
minPos.x = rand() % 100;
|
||||
minPos.y = rand() % 100;
|
||||
minPos.z = rand() % 100;
|
||||
maxPos.x = rand() % 100;
|
||||
maxPos.y = rand() % 100;
|
||||
maxPos.z = rand() % 100;
|
||||
|
||||
someAABB = AABB(minPos, maxPos);
|
||||
z = Collision::RayAABBIntr(ray, someAABB);
|
||||
if (z) ++test;
|
||||
}
|
||||
BOOST_CHECK(test >= 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(octTest)
|
||||
{
|
||||
glm::vec3 mini = glm::vec3(-1, -1, -1);
|
||||
glm::vec3 maxi = glm::vec3(1, 1, 1);
|
||||
OctTree tree(AABB(mini, maxi), 2);
|
||||
tree.AddBox(AABB(mini, -0.9f*maxi));
|
||||
OctTree::Output data;
|
||||
glm::vec3 origin = 3.0f * mini;
|
||||
BOOST_CHECK(tree.RayCollides({origin , glm::normalize(mini - origin) }, data));
|
||||
tree.ClearBoxes();
|
||||
BOOST_CHECK(!tree.RayCollides({ origin , glm::normalize(mini - origin) }, data));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include <boost/any.hpp>
|
||||
#include "GLM.h"
|
||||
#include "Core/World.h"
|
||||
#include "Core/Util/Any.h"
|
||||
|
||||
//octTree
|
||||
//#include <windows.h>
|
||||
|
||||
//last!
|
||||
#define private public
|
||||
#include <Engine\Core\OctTree.h>
|
||||
|
||||
class HardcodedTestWorld : public World
|
||||
{
|
||||
public:
|
||||
EntityID OctTreeEntityIdSaved;
|
||||
|
||||
//constructor
|
||||
HardcodedTestWorld()
|
||||
: World()
|
||||
{
|
||||
registerTestComponents();
|
||||
createTestEntities();
|
||||
}
|
||||
|
||||
private:
|
||||
void registerTestComponents()
|
||||
{
|
||||
ComponentWrapperFactory f;
|
||||
|
||||
|
||||
f = ComponentWrapperFactory("Test");
|
||||
f.AddProperty("TestInteger", 1337);
|
||||
f.AddProperty("TestFloat", 13.37f);
|
||||
f.AddProperty("TestString", std::string("Carlito"));
|
||||
RegisterComponent(f);
|
||||
|
||||
f = ComponentWrapperFactory("Debug");
|
||||
f.AddProperty("Name", std::string("Unnamed"));
|
||||
RegisterComponent(f);
|
||||
|
||||
f = ComponentWrapperFactory("Transform");
|
||||
f.AddProperty("Position", glm::vec3(0.f, 0.f, 0.f));
|
||||
f.AddProperty("Orientation", glm::quat());
|
||||
f.AddProperty("Scale", glm::vec3(1.f, 1.f, 1.f));
|
||||
RegisterComponent(f);
|
||||
|
||||
f = ComponentWrapperFactory("Model");
|
||||
f.AddProperty("Resource", std::string());
|
||||
f.AddProperty("Color", glm::vec4(1.f, 1.f, 1.f, 1.f));
|
||||
f.AddProperty("Visible", true);
|
||||
RegisterComponent(f);
|
||||
}
|
||||
|
||||
void createTestEntities()
|
||||
{
|
||||
World& world = *this;
|
||||
|
||||
// Create an entity
|
||||
EntityID e = world.CreateEntity();
|
||||
|
||||
// Attach a Debug component
|
||||
ComponentWrapper debug = world.AttachComponent(e, "Debug");
|
||||
// Set the Name field of the Debug component using subscript operator
|
||||
debug["Name"] = "Carlito";
|
||||
|
||||
// Attach a Transform component
|
||||
world.AttachComponent(e, "Transform");
|
||||
// Fetch the component based on EntityID and component type
|
||||
ComponentWrapper transform = world.GetComponent(e, "Transform");
|
||||
// Set the fields of the Transform component
|
||||
transform["Position"] = glm::vec3(0.f, 0.f, 0.f);
|
||||
transform["Scale"] = glm::vec3(1.f, 1.f, 1.f);
|
||||
|
||||
// Move on the X axis by fetching field as reference
|
||||
((glm::vec3&)transform["Position"]).x += 10.f;
|
||||
// Shrink by a factor of 100
|
||||
((glm::vec3&)transform["Scale"]) /= 100.f;
|
||||
|
||||
// Loop through all Transform components and print them
|
||||
for (auto& transform : world.GetComponents("Transform")) {
|
||||
glm::vec3 pos = transform["Position"];
|
||||
std::cout << "Position: " << pos.x << " " << pos.y << " " << pos.z << std::endl;
|
||||
glm::vec3 scale = transform["Scale"];
|
||||
std::cout << "Scale: " << scale.x << " " << scale.y << " " << scale.z << std::endl;
|
||||
|
||||
// Fetch the Debug component also present in this entity
|
||||
ComponentWrapper debug = world.GetComponent(transform.EntityID, "Debug");
|
||||
std::cout << "Name: " << (std::string)debug["Name"] << std::endl;
|
||||
}
|
||||
|
||||
//Create some test widgets
|
||||
//{
|
||||
// EntityID entityScaleWidget = world.CreateEntity();
|
||||
// ComponentWrapper transform = world.AttachComponent(entityScaleWidget, "Transform");
|
||||
// transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
|
||||
// ComponentWrapper model = world.AttachComponent(entityScaleWidget, "Model");
|
||||
// model["Resource"] = "Models/ScaleWidget.obj";
|
||||
//}
|
||||
//{
|
||||
// EntityID entityRotationWidget = world.CreateEntity();
|
||||
// ComponentWrapper transform = world.AttachComponent(entityRotationWidget, "Transform");
|
||||
// transform["Position"] = glm::vec3(1.5f, 0.f, 0.f);
|
||||
// ComponentWrapper model = world.AttachComponent(entityRotationWidget, "Model");
|
||||
// model["Resource"] = "Models/RotationWidget.obj";
|
||||
//}
|
||||
//{
|
||||
// EntityID entityDummyScene = world.CreateEntity();
|
||||
// ComponentWrapper transform = world.AttachComponent(entityDummyScene, "Transform");
|
||||
// transform["Position"] = glm::vec3(0, 0.f, 0.f);
|
||||
// ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model");
|
||||
// model["Resource"] = "Models/DummyScene.obj";
|
||||
//}
|
||||
|
||||
//add octTree
|
||||
{
|
||||
//ComponentWrapper debug = world.AttachComponent(e, "Debug");
|
||||
//// Set the Name field of the Debug component using subscript operator
|
||||
//debug["Name"] = "Blah";
|
||||
auto minCorner = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
auto maxCorner = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
auto someAABB = AABB(minCorner, maxCorner);
|
||||
|
||||
auto someOctTree = OctTree(someAABB, 2);
|
||||
|
||||
//auto min1 = someOctTree.m_Children[i]->m_Box.MinCorner();
|
||||
//auto max1 = someOctTree.m_Children[i]->m_Box.MaxCorner();
|
||||
|
||||
float boxDrawFactor = 1.05f;
|
||||
auto halfSizeFactor = 0.0f;
|
||||
halfSizeFactor = someAABB.HalfSize().x;
|
||||
|
||||
//the first box first
|
||||
EntityID entityDummyScene = world.CreateEntity();
|
||||
|
||||
ComponentWrapper transform = world.AttachComponent(entityDummyScene, "Transform");
|
||||
transform["Position"] = someAABB.Center()*1.0f;
|
||||
transform["Scale"] = glm::vec3(1.0f, 1.0f, 1.0f)*halfSizeFactor*boxDrawFactor;
|
||||
|
||||
ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model");
|
||||
model["Resource"] = "Models/Core/UnitBox.obj";
|
||||
model["Color"] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
//just draw the first 8 children - looks nicer in code if i split it this way
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
{
|
||||
auto cen1 = someOctTree.m_Children[i]->m_Box.Center();
|
||||
halfSizeFactor = someOctTree.m_Children[i]->m_Box.HalfSize().x;
|
||||
|
||||
EntityID entityDummyScene = world.CreateEntity();
|
||||
|
||||
ComponentWrapper transform = world.AttachComponent(entityDummyScene, "Transform");
|
||||
transform["Position"] = cen1*1.0f;
|
||||
transform["Scale"] = glm::vec3(1.0f, 1.0f, 1.0f)*0.97f*halfSizeFactor*boxDrawFactor;
|
||||
|
||||
ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model");
|
||||
model["Resource"] = "Models/Core/UnitBox.obj";
|
||||
model["Color"] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
//OutputDebugStringA((std::to_string(cen1.x) + std::to_string(cen1.y) + std::to_string(cen1.z)).c_str());
|
||||
//OctTreeEntityIdSaved = entityDummyScene;
|
||||
}
|
||||
|
||||
//then draw the childrens children
|
||||
//for (size_t j = 0; j < 8; j++)
|
||||
//{
|
||||
// auto someChild = someOctTree.m_Children[j];
|
||||
|
||||
// for (size_t i = 0; i < 8; i++)
|
||||
// {
|
||||
// auto cen1 = someChild->m_Children[i]->m_Box.Center();
|
||||
// auto boxScale = someChild->m_Children[i]->m_Box.HalfSize();
|
||||
|
||||
// EntityID entityDummyScene = world.CreateEntity();
|
||||
|
||||
// ComponentWrapper transform = world.AttachComponent(entityDummyScene, "Transform");
|
||||
// transform["Position"] = cen1*1.0f;
|
||||
// transform["Scale"] = glm::vec3(1.0f, 1.0f, 1.0f)*0.97f*boxScale*boxDrawFactor;
|
||||
|
||||
// ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model");
|
||||
// model["Resource"] = "Models/Core/UnitBox.obj";
|
||||
// model["Color"] = glm::vec4(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
// //OctTreeEntityIdSaved = entityDummyScene;
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user