Merge branch 'OctTree' of github.com:teamfisk/TacticalZ into OctTree

This commit is contained in:
verysecrethero
2015-12-03 17:31:07 +01:00
10 changed files with 289 additions and 40 deletions
+24
View File
@@ -0,0 +1,24 @@
#ifndef AABB_h__
#define AABB_h__
#include "../GLM.h"
class AABB
{
public:
AABB() = default;
AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
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& HalfSize() const { return m_HalfSize; }
private:
glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner;
glm::vec3 m_Center;
glm::vec3 m_HalfSize;
};
#endif
+4 -25
View File
@@ -1,37 +1,16 @@
#ifndef Collision_h__
#define Collision_h__
#include "../GLM.h"
#include <algorithm>
#include "Core/Ray.h"
#include "Core/AABB.h"
namespace Collision
{
struct Ray
{
public:
glm::vec3 Origin;
glm::vec3 Direction;
};
class AABB
{
public:
AABB() = default;
AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
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& HalfSize() const { return m_HalfSize; }
private:
glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner;
glm::vec3 m_Center;
glm::vec3 m_HalfSize;
};
bool RayAABBIntr(const Ray& ray, const AABB& box);
bool RayVsAABB(const Ray& ray, const AABB& box);
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
}
#endif
+29
View File
@@ -1,5 +1,34 @@
#ifndef OctTree_h__
#define OctTree_h__
#include "Core/Collision.h"
class OctTree
{
public:
struct Output
{
float CollideDistance;
};
OctTree();
~OctTree();
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
OctTree(const AABB& octTreeBounds, int subDivisions);
void AddBox(const AABB& box);
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;
private:
OctTree* m_Children[8];
std::vector<AABB> 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.
AABB m_Box;
bool rayCollides(const Ray& ray, Output& data, const OctTree* const tree) const;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
};
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef Ray_h__
#define Ray_h__
#include "../GLM.h"
struct Ray
{
glm::vec3 Origin;
glm::vec3 Direction;
};
#endif // Ray_h__
+11
View File
@@ -0,0 +1,11 @@
#include "Core/AABB.h"
AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
: m_MinCorner(minPos)
, m_MaxCorner(maxPos)
, m_Center(0.5f * (maxPos + minPos))
, m_HalfSize(0.5f * (maxPos - minPos))
{}
AABB::~AABB()
{}
+9 -8
View File
@@ -1,16 +1,10 @@
#include "Core\Collision.h"
#include "Core/Collision.h"
#include "Engine/GLM.h"
#include <algorithm>
namespace Collision
{
AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
: m_MinCorner(minPos)
, m_MaxCorner(maxPos)
, m_Center(0.5f * (maxPos + minPos))
, m_HalfSize(0.5f * (maxPos - minPos))
{ }
bool RayAABBIntr(const Ray& ray, const AABB& box)
{
glm::vec3 w = 75.0f * ray.Direction;
@@ -38,6 +32,12 @@ bool RayAABBIntr(const Ray& ray, const AABB& box)
}
bool RayVsAABB(const Ray& ray, const AABB& box)
{
float dummy;
return RayVsAABB(ray, box, dummy);
}
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance)
{
glm::vec3 invdir = 1.0f / ray.Direction;
@@ -54,6 +54,7 @@ bool RayVsAABB(const Ray& ray, const AABB& box)
if (tmax < 0 || tmin > tmax)
return false;
outDistance = (tmin > 0) ? tmin : tmax;
return true;
}
+191
View File
@@ -0,0 +1,191 @@
#include <vector>
#include <algorithm>
#include <bitset>
#include "Core/OctTree.h"
namespace
{
//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;
}
}
OctTree::OctTree()
: OctTree(AABB(), 0)
{}
OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
: m_Box(octTreeBounds)
{
if (subDivisions == 0) {
for (OctTree*& c : m_Children) {
c = nullptr;
}
} else {
--subDivisions;
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.MaxCorner();
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 {
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 {
minPos.y = parentMin.y;
maxPos.y = parentCenter.y;
}
//If child is 1,3,5,7
if (bits.test(0)) {
minPos.z = parentCenter.z;
maxPos.z = parentMax.z;
} else {
minPos.z = parentMin.z;
maxPos.z = parentCenter.z;
}
m_Children[i] = new OctTree(AABB(minPos, maxPos), subDivisions);
}
}
}
OctTree::~OctTree()
{
for (OctTree*& c : m_Children) {
if (c != nullptr) {
delete c;
c = nullptr;
}
}
}
bool OctTree::RayCollides(const Ray& ray, Output& data) const
{
data.CollideDistance = -1;
return rayCollides(ray, data, this);
}
//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 OctTree* const tree) const
{
//If the node AABB is missed, everything it contains is missed.
if (Collision::RayAABBIntr(ray, tree->m_Box)) {
//If the ray shoots the tree, and it is a parent to 8 children :o
if (tree->hasChildren()) {
//Sort children according to their distance from the ray origin.
std::vector<ChildInfo> childInfos;
childInfos.reserve(8);
for (int i = 0; i < 8; ++i) {
childInfos.push_back({ i, glm::distance(ray.Origin, tree->m_Children[i]->m_Box.Center()) });
}
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 (rayCollides(ray, data, tree->m_Children[info.Index])) {
return true;
}
}
} else {
////TODO: Check against objects in the node.
//float minDist = INFINITY;
//for (const auto& obj : m_ObjectsInBox) {
// float dist = Collide(ray, obj);
// minDist = min(dist, minDist);
//}
//data.CollideDistance = minDist;
//if minDist != Collide()'s non-collide value: return false;
return true;
}
}
return false;
}
void OctTree::AddBox(const AABB& box)
{
if (hasChildren()) {
int minInd = childIndexContainingPoint(box.MinCorner());
int maxInd = childIndexContainingPoint(box.MaxCorner());
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.
bits.flip();
for (int c = 0; c < 8; ++c) {
if ((bits & std::bitset<3>(c))[0]) {
m_Children[c]->AddBox(box);
}
}
break;
case 3: //Eight children.
for (OctTree*& c : m_Children) {
c->AddBox(box);
}
break;
default:
break;
}
} else {
m_ContainingBoxes.push_back(box);
}
}
void OctTree::ClearBoxes()
{
if (hasChildren()) {
for (OctTree*& c : m_Children) {
c->ClearBoxes();
}
} else {
m_ContainingBoxes.clear();
}
}
//: 3 7
//:
//: 2 6
//: |
//: 1 5 \ y
//: z
//: 0 4 0 x-->
//
// child: 0 1 2 3 4 5 6 7
// x : - - - - + + + +
// y : - - + + - - + +
// z : - + - + - + - +
int OctTree::childIndexContainingPoint(const glm::vec3& point) const
{
const glm::vec3& c = m_Box.Center();
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
}
inline bool OctTree::hasChildren() const
{
return m_Children[0] != nullptr;
}
View File
+8 -6
View File
@@ -4,6 +4,8 @@
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
//vs memleaks
@@ -22,8 +24,8 @@ BOOST_AUTO_TEST_CASE(collisionTest)
//fixed seed
srand(2);
Collision::Ray ray;
Collision::AABB someAABB;
Ray ray;
AABB someAABB;
glm::vec3 minPos;
glm::vec3 maxPos;
bool z;
@@ -43,7 +45,7 @@ BOOST_AUTO_TEST_CASE(collisionTest)
maxPos.y = rand() % 100;
maxPos.z = rand() % 100;
someAABB = Collision::AABB(minPos, maxPos);
someAABB = AABB(minPos, maxPos);
z = Collision::RayVsAABB(ray, someAABB);
if (z) ++test;
}
@@ -56,8 +58,8 @@ BOOST_AUTO_TEST_CASE(collisionTest2)
{
//fixed seed
srand(2);
Collision::Ray ray;
Collision::AABB someAABB;
Ray ray;
AABB someAABB;
glm::vec3 minPos;
glm::vec3 maxPos;
bool z;
@@ -77,7 +79,7 @@ BOOST_AUTO_TEST_CASE(collisionTest2)
maxPos.y = rand() % 100;
maxPos.z = rand() % 100;
someAABB = Collision::AABB(minPos, maxPos);
someAABB = AABB(minPos, maxPos);
z = Collision::RayAABBIntr(ray, someAABB);
if (z) ++test;
}
+1 -1
View File
@@ -1,7 +1,7 @@
#include <boost/test/unit_test.hpp>
using boost::unit_test_framework::test_suite;
using boost::unit_test_framework::test_case;
#include "../wmem/MemPrototype/ObjectPool.h"
#include "Engine/Core/ObjectPool.h"
#include <ctime>
struct S