浏览代码

Visibility tests

Panagiotis Christopoulos Charitos 13 年之前
父节点
当前提交
554aca54bc

+ 2 - 3
include/anki/resource/ResourceManager.inl.h

@@ -18,8 +18,7 @@ void ResourceManager<Type>::allocAndLoadRsrc(
 	}
 	catch(const std::exception& e)
 	{
-		throw ANKI_EXCEPTION("Constructor failed for \"" + filename +
-			"\"") << e;
+		throw ANKI_EXCEPTION("Constructor failed for: " + filename) << e;
 	}
 
 	// Load
@@ -29,7 +28,7 @@ void ResourceManager<Type>::allocAndLoadRsrc(
 	}
 	catch(std::exception& e)
 	{
-		throw ANKI_EXCEPTION("Cannot load \"" + filename + "\"") << e;
+		throw ANKI_EXCEPTION("Cannot load: " + filename) << e;
 	}
 }
 

+ 3 - 11
include/anki/scene/ModelNode.h

@@ -64,6 +64,7 @@ public:
 		Movable::movableUpdate();
 		obb = modelPatch->getMeshBase().getBoundingShape().getTransformed(
 			getWorldTransform());
+		spatialMarkUpdated();
 	}
 	/// @}
 
@@ -95,7 +96,7 @@ private:
 };
 
 /// The model scene node
-class ModelNode: public SceneNode, public Movable, public Spatial
+class ModelNode: public SceneNode, public Movable
 {
 public:
 	typedef boost::ptr_vector<ModelPatchNode> ModelPatchNodes;
@@ -124,12 +125,6 @@ public:
 		return this;
 	}
 
-	/// Override SceneNode::getSpatial()
-	Spatial* getSpatial()
-	{
-		return this;
-	}
-
 	/// Override SceneNode::frameUpdate
 	void frameUpdate(float prevUpdateTime, float crntTime, int frame)
 	{
@@ -145,15 +140,12 @@ public:
 	void movableUpdate()
 	{
 		Movable::movableUpdate();
-		obb = model->getVisibilityShape().getTransformed(
-			getWorldTransform());
 	}
 	/// @}
 
-//private:
+private:
 	ModelResourcePointer model; ///< The resource
 	ModelPatchNodes patches;
-	Obb obb;
 };
 
 } // end namespace

+ 44 - 30
include/anki/scene/Octree.h

@@ -2,26 +2,31 @@
 #define ANKI_SCENE_OCTREE_H
 
 #include "anki/collision/Aabb.h"
-#include <boost/array.hpp>
-#include <boost/ptr_container/ptr_vector.hpp>
+#include "anki/util/Vector.h"
+#include <array>
+#include <memory>
 
 namespace anki {
 
-/// XXX
+class Spatial;
+
+/// Octree node
 class OctreeNode
 {
+	friend class Octree;
+
 public:
+	typedef std::array<std::unique_ptr<OctreeNode>, 8> ChildrenContainer;
+
 	OctreeNode(const Aabb& aabb_, OctreeNode* parent_)
 		: parent(parent_), aabb(aabb_)
-	{
-		initArr();
-	}
+	{}
 
 	/// @name Accessors
 	/// @{
-	const boost::array<OctreeNode*, 8>& getChildren() const
+	const OctreeNode* getChild(uint32_t id) const
 	{
-		return children;
+		return children[id].get();
 	}
 
 	const OctreeNode* getParent() const
@@ -33,34 +38,40 @@ public:
 	{
 		return aabb;
 	}
+
+	Vector<Spatial*>::iterator getSpatialsBegin()
+	{
+		return spatials.begin();
+	}
+	Vector<Spatial*>::iterator getSpatialsEnd()
+	{
+		return spatials.end();
+	}
+	uint32_t getSpatialsCount() const
+	{
+		return spatials.size();
+	}
 	/// @}
 
 	bool isRoot() const
 	{
-		return parent == NULL;
+		return parent == nullptr;
 	}
 
-	void addChild(uint pos, OctreeNode& child)
+	void addChild(uint32_t pos, OctreeNode* child)
 	{
-		child.parent = this;
-		children[pos] = &child;
+		child->parent = this;
+		children[pos].reset(child);
 	}
 
 private:
-	boost::array<OctreeNode*, 8> children;
+	ChildrenContainer children;
 	OctreeNode* parent;
 	Aabb aabb; ///< Including AABB
-
-	void initArr()
-	{
-		for(size_t i = 0; i < children.size(); ++i)
-		{
-			children[i] = NULL;
-		}
-	}
+	Vector<Spatial*> spatials;
 };
 
-/// XXX
+/// Octree
 class Octree
 {
 public:
@@ -70,28 +81,31 @@ public:
 	/// @{
 	const OctreeNode& getRoot() const
 	{
-		return *root;
+		return root;
 	}
 	OctreeNode& getRoot()
 	{
-		return *root;
+		return root;
 	}
 
-	uint getMaxDepth() const
+	uint32_t getMaxDepth() const
 	{
 		return maxDepth;
 	}
 	/// @}
 
+	void placeSpatial(Spatial* sp);
+
+	/// Place an AABB inside the tree. The algorithm is pretty simple, find the
+	/// node that completely includes the aabb. If found then go deeper into
+	/// the node's children. The aabb will not be in more than one nodes. Also,
+	/// if it is ourside the tree then return nullptr
 	OctreeNode* place(const Aabb& aabb);
 
 private:
-	OctreeNode* root = nullptr;
-	boost::ptr_vector<OctreeNode> nodes; ///< For garbage collection
-	uint maxDepth;
+	uint32_t maxDepth;
 	float looseness;
-
-	//void createSubTree(uint rdepth, OctreeNode& parent);
+	OctreeNode root;
 
 	OctreeNode* place(const Aabb& aabb, uint depth, OctreeNode& node);
 

+ 1 - 1
include/anki/scene/Scene.h

@@ -108,7 +108,7 @@ public:
 		return (it == nameToNode.end()) ? nullptr : it->second;
 	}
 
-	Vector<Sector> sectors;
+	PtrVector<Sector> sectors;
 
 private:
 	Types<SceneNode>::Container nodes;

+ 9 - 0
include/anki/scene/Sector.h

@@ -5,6 +5,9 @@
 
 namespace anki {
 
+class Spatial;
+
+/// A sector
 class Sector
 {
 public:
@@ -16,6 +19,12 @@ public:
 	{
 		return octree;
 	}
+	Octree& getOctree()
+	{
+		return octree;
+	}
+
+	bool placeSpatial(Spatial* sp);
 
 private:
 	Octree octree;

+ 24 - 1
include/anki/scene/Spatial.h

@@ -7,6 +7,8 @@
 
 namespace anki {
 
+class OctreeNode;
+
 /// @addtogroup Scene
 /// @{
 
@@ -35,10 +37,28 @@ public:
 		return *spatialCs;
 	}
 
+	const Aabb& getAabb() const
+	{
+		return aabb;
+	}
+
 	uint32_t getSpatialLastUpdateFrame() const
 	{
 		return lastUpdateFrame;
 	}
+
+	OctreeNode* getOctreeNode()
+	{
+		return octreeNode;
+	}
+	const OctreeNode* getOctreeNode() const
+	{
+		return octreeNode;
+	}
+	void setOctreeNode(OctreeNode* x)
+	{
+		octreeNode = x;
+	}
 	/// @}
 
 	/// The derived class has to manually set when the collision shape got
@@ -46,13 +66,16 @@ public:
 	void spatialMarkUpdated()
 	{
 		lastUpdateFrame = SceneSingleton::get().getFramesCount();
+		spatialCs->getAabb(aabb);
 	}
 
 protected:
-	CollisionShape* spatialCs;
+	CollisionShape* spatialCs = nullptr;
 
 private:
 	uint32_t lastUpdateFrame = SceneSingleton::get().getFramesCount();
+	OctreeNode* octreeNode = nullptr; ///< What octree node includes this
+	Aabb aabb; ///< A faster shape
 };
 /// @}
 

+ 10 - 57
include/anki/util/Vector.h

@@ -3,7 +3,6 @@
 
 #include "anki/util/Assert.h"
 #include <vector>
-#include <cassert>
 
 namespace anki {
 
@@ -13,67 +12,21 @@ namespace anki {
 template<typename T>
 using Vector = std::vector<T>;
 
-#if 0
-/// This is a wrapper of Vector that adds new functionality and assertions
-/// in operator[]
-template<typename Type, typename Allocator = std::allocator<Type>>
-class Vector: public std::vector<Type, Allocator>
+template<typename T>
+class PtrVector: public Vector<T*>
 {
 public:
-	typedef Vector<Type, Allocator> Base;
-	typedef typename Base::value_type value_type;
-	typedef typename Base::allocator_type allocator_type;
-	typedef typename Base::size_type size_type;
-	typedef typename Base::reference reference;
-	typedef typename Base::const_reference const_reference;
-	typedef typename Base::iterator iterator;
-	typedef typename Base::const_iterator const_iterator;
-	typedef typename Base::pointer pointer;
-
-	/// @name Constructors & destructor
-	/// @{
-	Vector()
-		: Base()
-	{}
-
-	Vector(const allocator_type& a)
-		: Base(a)
-	{}
-
-	Vector(size_type n,
-		const value_type& value = value_type(),
-		const allocator_type& a = allocator_type())
-		: Base(n, value, a)
-	{}
-
-	Vector(const Vector& x)
-		: Base(x)
-	{}
-
-	template<typename InputIterator>
-	Vector(InputIterator first, InputIterator last,
-		const allocator_type& a = allocator_type())
-		: Base(first, last, a)
-	{}
-	/// @}
-
-	/// @name Accessors
-	/// @{
-	reference operator[](size_type n)
+	~PtrVector()
 	{
-		ANKI_ASSERT(n < Base::size());
-		return Base::operator[](n);
+		for(typename Vector<T*>::iterator it = Vector<T*>::begin();
+			it != Vector<T*>::end(); it++)
+		{
+			typedef char TypeMustBeComplete[sizeof(T) ? 1 : -1];
+    		(void) sizeof(TypeMustBeComplete);
+			delete *it;
+		}
 	}
-
-	const_reference operator[](size_type n) const
-	{
-		ANKI_ASSERT(n < Base::size());
-		return Base::operator[](n);
-	}
-	/// @}
 };
-#endif
-/// @}
 
 } // end namespace anki
 

+ 3 - 1
src/collision/Frustum.cpp

@@ -103,7 +103,9 @@ void PerspectiveFrustum::setTransform(const Transform& trf_)
 //==============================================================================
 void PerspectiveFrustum::getAabb(Aabb& aabb) const
 {
-	aabb.set(dirs);
+	std::array<Vec3, 5> points = {{
+		dirs[0], dirs[1], dirs[2], dirs[3], Vec3(0.0)}};
+	aabb.set(points);
 	aabb.getMin() += eye;
 	aabb.getMax() += eye;
 }

+ 3 - 3
src/renderer/Dbg.cpp

@@ -66,10 +66,10 @@ void Dbg::run()
 		sceneDrawer->draw(*node);
 	}
 
-	/*for(const Sector& sector : scene.sectors)
+	for(const Sector* sector : scene.sectors)
 	{
-		sceneDrawer->draw(sector.getOctree());
-	}*/
+		sceneDrawer->draw(sector->getOctree());
+	}
 }
 
 } // end namespace anki

+ 15 - 8
src/renderer/Drawer.cpp

@@ -461,10 +461,12 @@ void SceneDebugDrawer::draw(Frustumable& fr) const
 //==============================================================================
 void SceneDebugDrawer::draw(Spatial& x) const
 {
-	const CollisionShape& cs = x.getSpatialCollisionShape();
+	/*const CollisionShape& cs = x.getSpatialCollisionShape();
 
 	CollisionDebugDrawer coldraw(dbg);
-	cs.accept(coldraw);
+	cs.accept(coldraw);*/
+	CollisionDebugDrawer coldraw(dbg);
+	x.getAabb().accept(coldraw);
 }
 
 //==============================================================================
@@ -478,18 +480,23 @@ void SceneDebugDrawer::draw(const Octree& octree) const
 void SceneDebugDrawer::draw(const OctreeNode& octnode, uint32_t depth,
 	const Octree& octree) const
 {
-	Vec3 color = Vec3(1.0 - float(depth) / float(octree.getMaxDepth()));
-	dbg->setColor(color);
+	// Draw if it has spatials
+	if(octnode.getSpatialsCount() != 0)
+	{
+		//Vec3 color = Vec3(1.0 - float(depth) / float(octree.getMaxDepth()));
+		Vec3 color(1.0);
+		dbg->setColor(color);
 
-	CollisionDebugDrawer v(dbg);
-	octnode.getAabb().accept(v);
+		CollisionDebugDrawer v(dbg);
+		octnode.getAabb().accept(v);
+	}
 
 	// Children
 	for(uint32_t i = 0; i < 8; ++i)
 	{
-		if(octnode.getChildren()[i] != NULL)
+		if(octnode.getChild(i) != nullptr)
 		{
-			draw(*octnode.getChildren()[i], depth + 1, octree);
+			draw(*octnode.getChild(i), depth + 1, octree);
 		}
 	}
 }

+ 2 - 3
src/scene/ModelNode.cpp

@@ -26,8 +26,7 @@ ModelPatchNode::ModelPatchNode(const ModelPatch* modelPatch_,
 ModelNode::ModelNode(const char* modelFname,
 	const char* name, Scene* scene,
 	uint movableFlags, Movable* movParent)
-	: SceneNode(name, scene), Movable(movableFlags, movParent, *this),
-		Spatial(&obb)
+	: SceneNode(name, scene), Movable(movableFlags, movParent, *this)
 {
 	model.load(modelFname);
 
@@ -49,4 +48,4 @@ ModelNode::ModelNode(const char* modelFname,
 ModelNode::~ModelNode()
 {}
 
-} // end namespace
+} // end namespace anki

+ 55 - 17
src/scene/Octree.cpp

@@ -1,4 +1,5 @@
 #include "anki/scene/Octree.h"
+#include "anki/scene/Spatial.h"
 #include "anki/util/Exception.h"
 #include "anki/core/Logger.h"
 #include "anki/collision/CollisionAlgorithmsMatrix.h"
@@ -7,25 +8,58 @@ namespace anki {
 
 //==============================================================================
 Octree::Octree(const Aabb& aabb, uint8_t maxDepth_, float looseness_)
-:	maxDepth(maxDepth_ < 1 ? 1 : maxDepth_),
- 	looseness(looseness_)
+	: maxDepth(maxDepth_ < 1 ? 1 : maxDepth_), looseness(looseness_),
+		root(aabb, nullptr)
+{}
+
+//==============================================================================
+void Octree::placeSpatial(Spatial* sp)
 {
-	// Create root
-	root = new OctreeNode(aabb, NULL);
-	nodes.push_back(root);
+	OctreeNode* toBePlacedNode = place(sp->getAabb());
+
+	if(toBePlacedNode == nullptr)
+	{
+		ANKI_LOGI("Outside the whole tree");
+		// Outside the whole tree
+		return;
+	}
+
+	OctreeNode* crntNode = sp->getOctreeNode();
+
+	if(crntNode == toBePlacedNode)
+	{
+		ANKI_LOGI("Don't place in the same");
+		// Don't place in the same
+		return;
+	}
+
+	// Remove from current node
+	if(crntNode)
+	{
+		Vector<Spatial*>::iterator it =
+			std::find(crntNode->spatials.begin(), crntNode->spatials.end(), sp);
+
+		ANKI_ASSERT(it != crntNode->spatials.end());
+		crntNode->spatials.erase(it);
+	}
+
+	// Add to new one node
+	toBePlacedNode->spatials.push_back(sp);
+	sp->setOctreeNode(toBePlacedNode);
 }
 
 //==============================================================================
 OctreeNode* Octree::place(const Aabb& aabb)
 {
-	if(CollisionAlgorithmsMatrix::collide(aabb, root->getAabb()))
+	if(CollisionAlgorithmsMatrix::collide(aabb, root.aabb))
 	{
-		// Run the recursive
-		return place(aabb, 0, *root);
+		// Run the recursive method
+		return place(aabb, 0, root);
 	}
 	else
 	{
-		return NULL;
+		// Its completely outside the octree
+		return nullptr;
 	}
 }
 
@@ -45,29 +79,33 @@ OctreeNode* Octree::place(const Aabb& aabb, uint32_t depth, OctreeNode& node)
 			{
 				uint32_t id = i * 4 + j * 2 + k;
 
+				// Get the node's AABB. If there is no node then calculate the
+				// AABB
 				Aabb childAabb;
-				if(node.getChildren()[id] != NULL)
+				if(node.children[id].get() != nullptr)
 				{
-					childAabb = node.getChildren()[id]->getAabb();
+					// There is a child
+					childAabb = node.children[id]->aabb;
 				}
 				else
 				{
-					calcAabb(i, j, k, node.getAabb(), childAabb);
+					// Calculate
+					calcAabb(i, j, k, node.aabb, childAabb);
 				}
 
 				// If aabb its completely inside the target
 				if(aabb.getMax() <= childAabb.getMax() &&
 					aabb.getMin() >= childAabb.getMin())
 				{
-					// Create new node if needed
-					if(node.getChildren()[id] == NULL)
+					// Go deeper
+					if(node.children[id].get() == nullptr)
 					{
+						// Create new node if needed
 						OctreeNode* newNode = new OctreeNode(childAabb, &node);
-						node.addChild(id, *newNode);
-						nodes.push_back(newNode);
+						node.addChild(id, newNode);
 					}
 
-					return place(aabb, depth + 1, *node.getChildren()[id]);
+					return place(aabb, depth + 1, *node.children[id]);
 				}
 			} // k
 		} // j

+ 20 - 1
src/scene/Scene.cpp

@@ -32,9 +32,9 @@ void Scene::unregisterNode(SceneNode* node)
 //==============================================================================
 void Scene::update(float prevUpdateTime, float crntTime)
 {
+	// First do the movable updates
 	for(SceneNode* n : nodes)
 	{
-		n->frameUpdate(prevUpdateTime, crntTime, frame);
 		Movable* m = n->getMovable();
 		if(m)
 		{
@@ -42,6 +42,25 @@ void Scene::update(float prevUpdateTime, float crntTime)
 		}
 	}
 
+	// Then the rest
+	for(SceneNode* n : nodes)
+	{
+		n->frameUpdate(prevUpdateTime, crntTime, frame);
+
+		Spatial* sp = n->getSpatial();
+		if(sp && sp->getSpatialLastUpdateFrame() == frame)
+		{
+			for(Sector* sector : sectors)
+			{
+				if(sector->placeSpatial(sp))
+				{
+					ANKI_LOGI("Placing: " << n->getName());
+					continue;
+				}
+			}
+		}
+	}
+
 	doVisibilityTests(*mainCam);
 
 #if 0

+ 22 - 0
src/scene/Sector.cpp

@@ -0,0 +1,22 @@
+#include "anki/scene/Sector.h"
+#include "anki/scene/Spatial.h"
+#include "anki/collision/CollisionAlgorithmsMatrix.h"
+
+namespace anki {
+
+//==============================================================================
+bool Sector::placeSpatial(Spatial* sp)
+{
+	// XXX Optimize
+
+	if(!CollisionAlgorithmsMatrix::collide(sp->getAabb(),
+		octree.getRoot().getAabb()))
+	{
+		return false;
+	}
+
+	octree.placeSpatial(sp);
+	return true;
+}
+
+} // end namespace anki

+ 5 - 65
testapp/Main.cpp

@@ -99,7 +99,7 @@ void init()
 		1.0));
 
 	// Sectors
-	scene.sectors.push_back(Sector(Aabb(Vec3(-10.0), Vec3(10.0))));
+	scene.sectors.push_back(new Sector(Aabb(Vec3(-10.0), Vec3(10.0))));
 }
 
 //==============================================================================
@@ -121,6 +121,10 @@ void mainLoopExtra()
 	{
 		mover = &SceneSingleton::get().getActiveCamera();
 	}
+	if(in.getKey(SDL_SCANCODE_2))
+	{
+		mover = SceneSingleton::get().findSceneNode("horse")->getMovable();
+	}
 	if(in.getKey(SDL_SCANCODE_3))
 	{
 		mover = SceneSingleton::get().findSceneNode("spot0")->getMovable();
@@ -173,53 +177,6 @@ void mainLoop()
 	HighRezTimer::Scalar prevUpdateTime = HighRezTimer::getCurrentTime();
 	HighRezTimer::Scalar crntTime = prevUpdateTime;
 
-	const char* vert = R"(
-in vec3 position;
-uniform mat4 mvp;
-
-void main() {
-	gl_Position = mvp * vec4(position, 1.0);
-})";
-
-	const char* frag = R"(
-out vec3 fColor;
-void main() 
-{
-	fColor = vec3(0.0, 1.0, 0.0);
-})";
-
-	const char* trf[] = {nullptr};
-
-	ShaderProgram sprog;
-	sprog.create(vert, nullptr, nullptr, nullptr, frag, trf);
-
-	Vec3 maxPos = Vec3(0.5 * 1.0);
-	Vec3 minPos = Vec3(-0.5 * 1.0);
-
-	std::array<Vec3, 8> points = {{
-		Vec3(maxPos.x(), maxPos.y(), maxPos.z()),  // right top front
-		Vec3(minPos.x(), maxPos.y(), maxPos.z()),  // left top front
-		Vec3(minPos.x(), minPos.y(), maxPos.z()),  // left bottom front
-		Vec3(maxPos.x(), minPos.y(), maxPos.z()),  // right bottom front
-		Vec3(maxPos.x(), maxPos.y(), minPos.z()),  // right top back
-		Vec3(minPos.x(), maxPos.y(), minPos.z()),  // left top back
-		Vec3(minPos.x(), minPos.y(), minPos.z()),  // left bottom back
-		Vec3(maxPos.x(), minPos.y(), minPos.z())   // right bottom back
-	}};
-
-	std::array<uint16_t, 24> indeces = {{0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6,
-		7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7}};
-
-	Vbo posvbo, idsvbo;
-
-	posvbo.create(GL_ARRAY_BUFFER, sizeof(points), &points[0], GL_STATIC_DRAW);
-	idsvbo.create(GL_ELEMENT_ARRAY_BUFFER, sizeof(indeces), &indeces[0], GL_STATIC_DRAW);
-
-	Vao vao;
-	vao.create();
-	vao.attachArrayBufferVbo(posvbo, 0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
-	vao.attachElementArrayBufferVbo(idsvbo);
-
 	while(1)
 	{
 		SceneSingleton::get().updateFrameStart();
@@ -236,23 +193,6 @@ void main()
 		EventManagerSingleton::get().updateAllEvents(prevUpdateTime, crntTime);
 		MainRendererSingleton::get().render(SceneSingleton::get());
 
-		Fbo::unbindAll();
-
-		/*glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-		glDisable(GL_DEPTH_TEST);*/
-
-		sprog.bind();
-		sprog.findUniformVariable("mvp").set(
-			cam->getProjectionMatrix() * cam->getViewMatrix());
-		//horse->model->getModelPatches()[0].getVao(PassLevelKey(0, 0)).bind();
-		vao.bind();
-
-		//int indeces = horse->model->getModelPatches()[0].getIndecesNumber(0);
-		int indeces = 24;
-		glDrawElements(GL_LINES,
-			indeces,
-			GL_UNSIGNED_SHORT, 0);
-
 		if(InputSingleton::get().getKey(SDL_SCANCODE_ESCAPE))
 		{
 			break;