From 32d2aa6a93c41a7ae8b9cf0ddbd534e3daf511d7 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 8 Dec 2015 17:01:50 +0100 Subject: [PATCH 1/2] AABB can also be created with center position and its size. --- include/Engine/Core/AABB.h | 4 ++++ src/Engine/Core/AABB.cpp | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/include/Engine/Core/AABB.h b/include/Engine/Core/AABB.h index 7d0a46ea..0a0adafa 100644 --- a/include/Engine/Core/AABB.h +++ b/include/Engine/Core/AABB.h @@ -7,12 +7,16 @@ class AABB { public: AABB() = default; + //No checks are made. Values in minPos must be less than values in maxPos, i.e. min.x < max.x, etc. AABB(const glm::vec3& minPos, const glm::vec3& maxPos); + //No checks are made. Size must consist of non-negative numbers. + virtual void CreateFromCenter(const glm::vec3& center, const glm::vec3& size); virtual ~AABB(); const glm::vec3& MinCorner() const { return m_MinCorner; } const glm::vec3& MaxCorner() const { return m_MaxCorner; } const glm::vec3& Center() const { return m_Center; } + const glm::vec3& Size() const { return 2.0f * m_HalfSize; } const glm::vec3& HalfSize() const { return m_HalfSize; } private: glm::vec3 m_MinCorner; diff --git a/src/Engine/Core/AABB.cpp b/src/Engine/Core/AABB.cpp index 8a364ce5..9da2bdb0 100644 --- a/src/Engine/Core/AABB.cpp +++ b/src/Engine/Core/AABB.cpp @@ -7,5 +7,13 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos) , m_HalfSize(0.5f * (maxPos - minPos)) {} +void AABB::CreateFromCenter(const glm::vec3& center, const glm::vec3& size) +{ + m_Center = center; + m_HalfSize = 0.5f * size; + m_MinCorner = m_Center - m_HalfSize; + m_MaxCorner = m_Center + m_HalfSize; +} + AABB::~AABB() {} From a7fb77d998bda9a745230c84c6d70c6f6c883784 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 8 Dec 2015 17:12:58 +0100 Subject: [PATCH 2/2] OctTree can check if a box collides with a box in the OctTree. --- include/Engine/Core/OctTree.h | 10 ++-- src/Engine/Core/OctTree.cpp | 98 +++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 43 deletions(-) diff --git a/include/Engine/Core/OctTree.h b/include/Engine/Core/OctTree.h index 1ae447a9..6279e93c 100644 --- a/include/Engine/Core/OctTree.h +++ b/include/Engine/Core/OctTree.h @@ -20,17 +20,21 @@ public: void ClearBoxes(); //Returns true if the ray collides with something in the tree. Result is written to [data]. bool RayCollides(const Ray& ray, Output& data) const; + //Returns true if the box collides with something in the tree. + //On collision with a box, that box is written to [outBoxIntersected]. + bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; private: OctTree* m_Children[8]; - std::vector m_ContainingBoxes; //TODO: Do derived class from AABB with a bool Tested, falsify at //start of Collision test, set on check, don't check if set already. Solves duplicate boxes in tree. + //TODO: Boxes collide with themselves? Fix somehow, maybe float epsilon stuff. + std::vector m_ContainingBoxes; AABB m_Box; - - bool rayCollides(const Ray& ray, Output& data) const; + inline bool hasChildren() const; int childIndexContainingPoint(const glm::vec3& point) const; + std::vector childIndicesContainingBox(const AABB& box) const; }; #endif \ No newline at end of file diff --git a/src/Engine/Core/OctTree.cpp b/src/Engine/Core/OctTree.cpp index e9aeb589..de38b143 100644 --- a/src/Engine/Core/OctTree.cpp +++ b/src/Engine/Core/OctTree.cpp @@ -48,7 +48,7 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions) minPos.x = parentMin.x; maxPos.x = parentCenter.x; } - + //If child is 2,3,6,7 if (bits.test(1)) { minPos.y = parentCenter.y; @@ -80,14 +80,25 @@ OctTree::~OctTree() } } -bool OctTree::RayCollides(const Ray& ray, Output& data) const +bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const { - data.CollideDistance = -1; - return rayCollides(ray, data); + if (hasChildren()) { + for (int i : childIndicesContainingBox(boxToTest)) { + if (m_Children[i]->BoxCollides(boxToTest, outBoxIntersected)) + return true; + } + } else { + for (const auto& objBox : m_ContainingBoxes) { + if (Collision::AABBVsAABB(boxToTest, objBox)) { + outBoxIntersected = objBox; + return true; + } + } + } + return false; } -//Currently all Nodes must have exactly 0 or 8 children, and objectdata should only exist in the last bottom nodes. -bool OctTree::rayCollides(const Ray& ray, Output& data) const +bool OctTree::RayCollides(const Ray& ray, Output& data) const { //If the node AABB is missed, everything it contains is missed. if (Collision::RayAABBIntr(ray, m_Box)) { @@ -102,7 +113,7 @@ bool OctTree::rayCollides(const Ray& ray, Output& data) const std::sort(childInfos.begin(), childInfos.end(), isFirstLower); //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. for (const ChildInfo& info : childInfos) { - if (m_Children[info.Index]->rayCollides(ray, data)) { + if (m_Children[info.Index]->RayCollides(ray, data)) { return true; } } @@ -127,39 +138,8 @@ bool OctTree::rayCollides(const Ray& ray, Output& data) const void OctTree::AddBox(const AABB& box) { if (hasChildren()) { - int minInd = childIndexContainingPoint(box.MinCorner()); - int maxInd = childIndexContainingPoint(box.MaxCorner()); - //Because of the predictable ordering of the child indices, - //the number of bits set when xor:ing the indices will determine the number of children containing the box. - std::bitset<3> bits(minInd ^ maxInd); - switch (bits.count()) { - case 0: //Box contained completely in one child. - m_Children[minInd]->AddBox(box); - break; - case 1: //Two children. - m_Children[minInd]->AddBox(box); - m_Children[maxInd]->AddBox(box); - break; - case 2: //Four children. - //Bit-hax to calculate the right 4 cildren containing the box. - //This works because of the childrens index determine what part of - //the dimensions they are responsible for (which octant). - bits.flip(); - //At this point the bits necessarily have exactly one bit set. - for (int c = 0; c < 8; ++c) { - //If the child index have the same bit set as the bits, add box to it. - if (bits.to_ulong() & c) { - m_Children[c]->AddBox(box); - } - } - break; - case 3: //Eight children. - for (OctTree*& c : m_Children) { - c->AddBox(box); - } - break; - default: - break; + for (auto i : childIndicesContainingBox(box)) { + m_Children[i]->AddBox(box); } } else { m_ContainingBoxes.push_back(box); @@ -196,6 +176,44 @@ int OctTree::childIndexContainingPoint(const glm::vec3& point) const return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z); } +std::vector OctTree::childIndicesContainingBox(const AABB& box) const +{ + int minInd = childIndexContainingPoint(box.MinCorner()); + int maxInd = childIndexContainingPoint(box.MaxCorner()); + //Because of the predictable ordering of the child indices, + //the number of bits set when xor:ing the indices will determine the number of children containing the box. + std::bitset<3> bits(minInd ^ maxInd); + switch (bits.count()) { + //Box contained completely in one child. + case 0: + return{ minInd }; + //Two children. + case 1: + return{ minInd, maxInd }; + //Four children. + case 2: + { + std::vector ret; + //Bit-hax to calculate the right 4 cildren containing the box. + //This works because of the childrens index determine what part of + //the dimensions they are responsible for (which octant). + bits.flip(); + //At this point the bits necessarily have exactly one bit set. + for (int c = 0; c < 8; ++c) { + //If the child index have the same bit set as the bits, add box to it. + if (bits.to_ulong() & c) { + ret.push_back(c); + } + } + return ret; + } + case 3: //Eight children. + return{ 0,1,2,3,4,5,6,7 }; + default: + return std::vector(); + } +} + inline bool OctTree::hasChildren() const { return m_Children[0] != nullptr;