From 8545b6ce6b1cc937aee0dfe03995089e4e290fae Mon Sep 17 00:00:00 2001 From: frohlich Date: Sun, 1 Mar 2009 12:35:49 +0000 Subject: [PATCH] Initial commit of the bounding volume tree implementation. The aim is to prove a better collion model in plenty ways. Added Files: .cvsignore BVHBoundingBoxVisitor.hxx BVHDebugCollectVisitor.hxx BVHGroup.cxx BVHGroup.hxx BVHLineGeometry.cxx BVHLineGeometry.hxx BVHLineSegmentVisitor.cxx BVHLineSegmentVisitor.hxx BVHMotionTransform.cxx BVHMotionTransform.hxx BVHNode.cxx BVHNode.hxx BVHStaticBinary.cxx BVHStaticBinary.hxx BVHStaticData.hxx BVHStaticGeometry.cxx BVHStaticGeometry.hxx BVHStaticGeometryBuilder.hxx BVHStaticLeaf.cxx BVHStaticLeaf.hxx BVHStaticNode.cxx BVHStaticNode.hxx BVHStaticTriangle.cxx BVHStaticTriangle.hxx BVHSubTreeCollector.cxx BVHSubTreeCollector.hxx BVHTransform.cxx BVHTransform.hxx BVHVisitor.hxx Makefile.am bvhtest.cxx --- simgear/scene/bvh/.cvsignore | 3 + simgear/scene/bvh/BVHBoundingBoxVisitor.hxx | 83 ++++++ simgear/scene/bvh/BVHDebugCollectVisitor.hxx | 222 +++++++++++++++ simgear/scene/bvh/BVHGroup.cxx | 88 ++++++ simgear/scene/bvh/BVHGroup.hxx | 61 +++++ simgear/scene/bvh/BVHLineGeometry.cxx | 49 ++++ simgear/scene/bvh/BVHLineGeometry.hxx | 53 ++++ simgear/scene/bvh/BVHLineSegmentVisitor.cxx | 157 +++++++++++ simgear/scene/bvh/BVHLineSegmentVisitor.hxx | 94 +++++++ simgear/scene/bvh/BVHMotionTransform.cxx | 111 ++++++++ simgear/scene/bvh/BVHMotionTransform.hxx | 113 ++++++++ simgear/scene/bvh/BVHNode.cxx | 72 +++++ simgear/scene/bvh/BVHNode.hxx | 67 +++++ simgear/scene/bvh/BVHStaticBinary.cxx | 45 +++ simgear/scene/bvh/BVHStaticBinary.hxx | 78 ++++++ simgear/scene/bvh/BVHStaticData.hxx | 55 ++++ simgear/scene/bvh/BVHStaticGeometry.cxx | 51 ++++ simgear/scene/bvh/BVHStaticGeometry.hxx | 56 ++++ .../scene/bvh/BVHStaticGeometryBuilder.hxx | 215 +++++++++++++++ simgear/scene/bvh/BVHStaticLeaf.cxx | 33 +++ simgear/scene/bvh/BVHStaticLeaf.hxx | 38 +++ simgear/scene/bvh/BVHStaticNode.cxx | 26 ++ simgear/scene/bvh/BVHStaticNode.hxx | 37 +++ simgear/scene/bvh/BVHStaticTriangle.cxx | 58 ++++ simgear/scene/bvh/BVHStaticTriangle.hxx | 54 ++++ simgear/scene/bvh/BVHSubTreeCollector.cxx | 258 ++++++++++++++++++ simgear/scene/bvh/BVHSubTreeCollector.hxx | 82 ++++++ simgear/scene/bvh/BVHTransform.cxx | 95 +++++++ simgear/scene/bvh/BVHTransform.hxx | 82 ++++++ simgear/scene/bvh/BVHVisitor.hxx | 58 ++++ simgear/scene/bvh/Makefile.am | 46 ++++ simgear/scene/bvh/bvhtest.cxx | 118 ++++++++ 32 files changed, 2658 insertions(+) create mode 100644 simgear/scene/bvh/.cvsignore create mode 100644 simgear/scene/bvh/BVHBoundingBoxVisitor.hxx create mode 100644 simgear/scene/bvh/BVHDebugCollectVisitor.hxx create mode 100644 simgear/scene/bvh/BVHGroup.cxx create mode 100644 simgear/scene/bvh/BVHGroup.hxx create mode 100644 simgear/scene/bvh/BVHLineGeometry.cxx create mode 100644 simgear/scene/bvh/BVHLineGeometry.hxx create mode 100644 simgear/scene/bvh/BVHLineSegmentVisitor.cxx create mode 100644 simgear/scene/bvh/BVHLineSegmentVisitor.hxx create mode 100644 simgear/scene/bvh/BVHMotionTransform.cxx create mode 100644 simgear/scene/bvh/BVHMotionTransform.hxx create mode 100644 simgear/scene/bvh/BVHNode.cxx create mode 100644 simgear/scene/bvh/BVHNode.hxx create mode 100644 simgear/scene/bvh/BVHStaticBinary.cxx create mode 100644 simgear/scene/bvh/BVHStaticBinary.hxx create mode 100644 simgear/scene/bvh/BVHStaticData.hxx create mode 100644 simgear/scene/bvh/BVHStaticGeometry.cxx create mode 100644 simgear/scene/bvh/BVHStaticGeometry.hxx create mode 100644 simgear/scene/bvh/BVHStaticGeometryBuilder.hxx create mode 100644 simgear/scene/bvh/BVHStaticLeaf.cxx create mode 100644 simgear/scene/bvh/BVHStaticLeaf.hxx create mode 100644 simgear/scene/bvh/BVHStaticNode.cxx create mode 100644 simgear/scene/bvh/BVHStaticNode.hxx create mode 100644 simgear/scene/bvh/BVHStaticTriangle.cxx create mode 100644 simgear/scene/bvh/BVHStaticTriangle.hxx create mode 100644 simgear/scene/bvh/BVHSubTreeCollector.cxx create mode 100644 simgear/scene/bvh/BVHSubTreeCollector.hxx create mode 100644 simgear/scene/bvh/BVHTransform.cxx create mode 100644 simgear/scene/bvh/BVHTransform.hxx create mode 100644 simgear/scene/bvh/BVHVisitor.hxx create mode 100644 simgear/scene/bvh/Makefile.am create mode 100644 simgear/scene/bvh/bvhtest.cxx diff --git a/simgear/scene/bvh/.cvsignore b/simgear/scene/bvh/.cvsignore new file mode 100644 index 00000000..e9955884 --- /dev/null +++ b/simgear/scene/bvh/.cvsignore @@ -0,0 +1,3 @@ +.deps +Makefile +Makefile.in diff --git a/simgear/scene/bvh/BVHBoundingBoxVisitor.hxx b/simgear/scene/bvh/BVHBoundingBoxVisitor.hxx new file mode 100644 index 00000000..8fc9db9f --- /dev/null +++ b/simgear/scene/bvh/BVHBoundingBoxVisitor.hxx @@ -0,0 +1,83 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHBoundingBoxVisitor_hxx +#define BVHBoundingBoxVisitor_hxx + +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" +#include "BVHMotionTransform.hxx" +#include "BVHLineGeometry.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" +#include "BVHStaticGeometry.hxx" + +namespace simgear { + +class BVHBoundingBoxVisitor : public BVHVisitor { +public: + virtual ~BVHBoundingBoxVisitor() {} + + void clear() + { _box.clear(); } + + virtual void apply(BVHGroup& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHTransform& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHMotionTransform& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHLineGeometry& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHStaticGeometry& node) + { expandBy(node.getBoundingSphere()); } + + virtual void apply(const BVHStaticBinary& node, const BVHStaticData& data) + { expandBy(node.getBoundingBox()); } + virtual void apply(const BVHStaticLeaf& node, const BVHStaticData& data) + { expandBy(node.computeBoundingBox(data)); } + virtual void apply(const BVHStaticTriangle& node, const BVHStaticData& data) + { expandBy(node.computeBoundingBox(data)); } + + const SGBoxf& getBox() const + { return _box; } + +private: + void expandBy(const SGSphered& sphere) + { + SGVec3f v0(sphere.getCenter() - sphere.getRadius()*SGVec3d(1, 1, 1)); + SGVec3f v1(sphere.getCenter() + sphere.getRadius()*SGVec3d(1, 1, 1)); + _box.expandBy(SGBoxf(v0, v1)); + } + void expandBy(const SGBoxf& box) + { _box.expandBy(box); } + + SGBoxf _box; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHDebugCollectVisitor.hxx b/simgear/scene/bvh/BVHDebugCollectVisitor.hxx new file mode 100644 index 00000000..540ee45f --- /dev/null +++ b/simgear/scene/bvh/BVHDebugCollectVisitor.hxx @@ -0,0 +1,222 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHDebugCollectVisitor_hxx +#define BVHDebugCollectVisitor_hxx + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" +#include "BVHMotionTransform.hxx" +#include "BVHStaticGeometry.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" + +#include "BVHBoundingBoxVisitor.hxx" + +namespace simgear { + +class BVHNode; +class BVHStaticNode; + +class BVHDebugCollectVisitor : public BVHVisitor { +public: + BVHDebugCollectVisitor(unsigned level = ~0u) : + _group(new osg::Group), + _level(level), + _currentLevel(0) + { + osg::StateSet* stateSet = _group->getOrCreateStateSet(); + stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateSet->setAttribute(new osg::Depth(osg::Depth::LESS, 0, 1, false)); + osg::BlendFunc *blendFunc; + blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, + osg::BlendFunc::DST_ALPHA); + stateSet->setAttributeAndModes(blendFunc); + osg::PolygonOffset* polygonOffset = new osg::PolygonOffset(-1, -1); + stateSet->setAttributeAndModes(polygonOffset); + } + virtual ~BVHDebugCollectVisitor() + { } + + virtual void apply(BVHGroup& node) + { + addNodeSphere(node); + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + } + virtual void apply(BVHTransform& node) + { + addNodeSphere(node); + osg::ref_ptr oldGroup = _group; + osg::ref_ptr transform = new osg::MatrixTransform; + transform->setMatrix(osg::Matrix(node.getToWorldTransform().data())); + _group = transform; + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + _group = oldGroup; + if (transform->getNumChildren()) + _group->addChild(transform.get()); + } + virtual void apply(BVHMotionTransform& node) + { + addNodeSphere(node); + osg::ref_ptr oldGroup = _group; + osg::ref_ptr transform; + transform = new osg::PositionAttitudeTransform; + double tt = node.getReferenceTime() - node.getEndTime(); + tt = 100*tt; + tt += node.getReferenceTime(); +// transform->setPosition(node.getPosition(node.getEndTime()).osg()); + transform->setPosition(node.getPosition().osg()); + transform->setAttitude(inverse(node.getOrientation(tt)).osg()); +// transform->setPosition(node.getPosition().osg()); +// transform->setAttitude(inverse(node.getOrientation()).osg()); + _group = transform; + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + _group = oldGroup; + if (transform->getNumChildren()) + _group->addChild(transform.get()); + } + virtual void apply(BVHLineGeometry&) + { + } + virtual void apply(BVHStaticGeometry& node) + { + addNodeSphere(node); + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + } + + virtual void apply(const BVHStaticBinary& node, const BVHStaticData& data) + { + addNodeBox(node, data); + ++_currentLevel; + node.traverse(*this, data); + --_currentLevel; + } + virtual void apply(const BVHStaticLeaf& node, const BVHStaticData& data) + { + addNodeBox(node, data); + } + virtual void apply(const BVHStaticTriangle& node, const BVHStaticData& data) + { + addNodeBox(node, data); + addTriangle(node.getTriangle(data), osg::Vec4(0.5, 0, 0.5, 0.2)); + } + + osg::Node* getNode() const { return _group.get(); } + + static unsigned allLevels() { return ~0u; } + static unsigned triangles() { return ~0u - 1; } + +private: + void addTriangle(const SGTrianglef& triangle, const osg::Vec4& color) + { + if (_level != triangles()) + return; + + osg::Geometry* geometry = new osg::Geometry; + + osg::Vec3Array* vertices = new osg::Vec3Array; + vertices->push_back(triangle.getVertex(0).osg()); + vertices->push_back(triangle.getVertex(1).osg()); + vertices->push_back(triangle.getVertex(2).osg()); + + osg::Vec4Array* colors = new osg::Vec4Array; + colors->push_back(color); + + geometry->setVertexArray(vertices); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_OVERALL); + + geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, 3)); + + osg::Geode* geode = new osg::Geode; + geode->addDrawable(geometry); + _group->addChild(geode); + } + + void addNodeSphere(const BVHNode& node) + { + if (_level != ~0u && _level != _currentLevel) + return; + SGSphered sphere = node.getBoundingSphere(); + osg::Sphere* shape = new osg::Sphere; + shape->setCenter(SGVec3f(sphere.getCenter()).osg()); + shape->setRadius(sphere.getRadius()); + addShape(shape, osg::Vec4(0.5f, 0.5f, 0.5f, 0.1f)); + } + + void addNodeBox(const BVHStaticNode& node, const BVHStaticData& data) + { + if (_level != ~0u && _level != _currentLevel) + return; + BVHBoundingBoxVisitor bbv; + node.accept(bbv, data); + osg::Box* shape = new osg::Box; + shape->setCenter(bbv.getBox().getCenter().osg()); + shape->setHalfLengths((0.5*bbv.getBox().getSize()).osg()); + addShape(shape, osg::Vec4(0.5f, 0, 0, 0.1f)); + } + + void addShape(osg::Shape* shape, const osg::Vec4& color) + { + osg::ShapeDrawable* shapeDrawable = new osg::ShapeDrawable; + shapeDrawable->setColor(color); + shapeDrawable->setShape(shape); + osg::Geode* geode = new osg::Geode; + geode->addDrawable(shapeDrawable); + _group->addChild(geode); + } + + osg::ref_ptr _group; + const unsigned _level; + unsigned _currentLevel; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHGroup.cxx b/simgear/scene/bvh/BVHGroup.cxx new file mode 100644 index 00000000..4fbba4a3 --- /dev/null +++ b/simgear/scene/bvh/BVHGroup.cxx @@ -0,0 +1,88 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHGroup.hxx" + +#include + +namespace simgear { + +BVHGroup::BVHGroup() +{ +} + +BVHGroup::~BVHGroup() +{ + ChildList::iterator i; + for (i = _children.begin(); i != _children.end(); ++i) { + (*i)->removeParent(this); + *i = 0; + } +} + +void +BVHGroup::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +void +BVHGroup::clear() +{ + _children.clear(); + invalidateBound(); +} + +void +BVHGroup::addChild(BVHNode* child) +{ + if (!child) + return; + ChildList::iterator i; + i = std::find(_children.begin(), _children.end(), child); + if (i != _children.end()) + return; + invalidateBound(); + child->addParent(this); + _children.push_back(child); +} + +void +BVHGroup::removeChild(BVHNode* child) +{ + if (!child) + return; + ChildList::iterator i; + i = std::find(_children.begin(), _children.end(), child); + if (i == _children.end()) + return; + invalidateBound(); + child->removeParent(this); + _children.erase(i); +} + +SGSphered +BVHGroup::computeBoundingSphere() const +{ + SGSphered sphere; + ChildList::const_iterator i; + for (i = _children.begin(); i != _children.end(); ++i) + sphere.expandBy((*i)->getBoundingSphere()); + return sphere; +} + +} diff --git a/simgear/scene/bvh/BVHGroup.hxx b/simgear/scene/bvh/BVHGroup.hxx new file mode 100644 index 00000000..d0b58363 --- /dev/null +++ b/simgear/scene/bvh/BVHGroup.hxx @@ -0,0 +1,61 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHGroup_hxx +#define BVHGroup_hxx + +#include +#include "BVHNode.hxx" +#include "BVHVisitor.hxx" + +namespace simgear { + +class BVHGroup : public BVHNode { +public: + BVHGroup(); + virtual ~BVHGroup(); + + virtual void accept(BVHVisitor& visitor); + + void traverse(BVHVisitor& visitor) + { + ChildList::const_iterator i; + for (i = _children.begin(); i != _children.end(); ++i) + (*i)->accept(visitor); + } + + void clear(); + void addChild(BVHNode* child); + void removeChild(BVHNode* child); + + unsigned getNumChildren() const + { return _children.size(); } + const BVHNode* getChild(unsigned i) const + { if (_children.size() <= i) return 0; return _children[i]; } + BVHNode* getChild(unsigned i) + { if (_children.size() <= i) return 0; return _children[i]; } + + virtual SGSphered computeBoundingSphere() const; + +private: + typedef std::vector > ChildList; + ChildList _children; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHLineGeometry.cxx b/simgear/scene/bvh/BVHLineGeometry.cxx new file mode 100644 index 00000000..679a4675 --- /dev/null +++ b/simgear/scene/bvh/BVHLineGeometry.cxx @@ -0,0 +1,49 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHLineGeometry.hxx" + +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHLineGeometry::BVHLineGeometry(const SGLineSegmentf& lineSegment, Type type) : + _lineSegment(lineSegment), + _type(type) +{ +} + +BVHLineGeometry::~BVHLineGeometry() +{ +} + +void +BVHLineGeometry::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +SGSphered +BVHLineGeometry::computeBoundingSphere() const +{ + SGSphered sphere; + sphere.expandBy(SGVec3d(_lineSegment.getStart())); + sphere.expandBy(SGVec3d(_lineSegment.getEnd())); + return sphere; +} + +} diff --git a/simgear/scene/bvh/BVHLineGeometry.hxx b/simgear/scene/bvh/BVHLineGeometry.hxx new file mode 100644 index 00000000..d0d87211 --- /dev/null +++ b/simgear/scene/bvh/BVHLineGeometry.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHLineGeometry_hxx +#define BVHLineGeometry_hxx + +#include +#include "BVHNode.hxx" + +namespace simgear { + +class BVHLineGeometry : public BVHNode { +public: + enum Type { + CarrierCatapult, + CarrierWire + }; + + BVHLineGeometry(const SGLineSegmentf& lineSegment, Type type); + virtual ~BVHLineGeometry(); + + virtual void accept(BVHVisitor& visitor); + + const SGLineSegmentf& getLineSegment() const + { return _lineSegment; } + + Type getType() const + { return _type; } + + virtual SGSphered computeBoundingSphere() const; + +private: + SGLineSegmentf _lineSegment; + Type _type; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHLineSegmentVisitor.cxx b/simgear/scene/bvh/BVHLineSegmentVisitor.cxx new file mode 100644 index 00000000..d4dbd194 --- /dev/null +++ b/simgear/scene/bvh/BVHLineSegmentVisitor.cxx @@ -0,0 +1,157 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHLineSegmentVisitor.hxx" + +#include + +#include "BVHVisitor.hxx" + +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" +#include "BVHMotionTransform.hxx" +#include "BVHLineGeometry.hxx" +#include "BVHStaticGeometry.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" + +namespace simgear { + +void +BVHLineSegmentVisitor::apply(BVHGroup& group) +{ + if (!intersects(_lineSegment, group.getBoundingSphere())) + return; + group.traverse(*this); +} + +void +BVHLineSegmentVisitor::apply(BVHTransform& transform) +{ + if (!intersects(_lineSegment, transform.getBoundingSphere())) + return; + + bool haveHit = _haveHit; + _haveHit = false; + + // Push the line segment + SGLineSegmentd lineSegment = getLineSegment(); + _lineSegment = transform.lineSegmentToLocal(lineSegment); + + transform.traverse(*this); + + if (_haveHit) { + _linearVelocity = transform.vecToWorld(_linearVelocity); + _angularVelocity = transform.vecToWorld(_angularVelocity); + SGVec3d point(transform.ptToWorld(_lineSegment.getEnd())); + _lineSegment.set(lineSegment.getStart(), point); + _normal = transform.vecToWorld(_normal); + } else { + _lineSegment = lineSegment; + _haveHit = haveHit; + } +} + +void +BVHLineSegmentVisitor::apply(BVHMotionTransform& transform) +{ + if (!intersects(_lineSegment, transform.getBoundingSphere())) + return; + + bool haveHit = _haveHit; + _haveHit = false; + + // Push the line segment + SGLineSegmentd lineSegment = getLineSegment(); + SGMatrixd toLocal = transform.getToLocalTransform(_time); + _lineSegment = lineSegment.transform(toLocal); + + transform.traverse(*this); + + if (_haveHit) { + SGMatrixd toWorld = transform.getToWorldTransform(_time); + SGVec3d localStart = _lineSegment.getStart(); + _linearVelocity += transform.getLinearVelocityAt(localStart); + _angularVelocity += transform.getAngularVelocity(); + _linearVelocity = toWorld.xformVec(_linearVelocity); + _angularVelocity = toWorld.xformVec(_angularVelocity); + SGVec3d localEnd = _lineSegment.getEnd(); + _lineSegment.set(lineSegment.getStart(), toWorld.xformPt(localEnd)); + _normal = toWorld.xformVec(_normal); + } else { + _lineSegment = lineSegment; + _haveHit = haveHit; + } +} + +void +BVHLineSegmentVisitor::apply(BVHLineGeometry&) +{ +} + +void +BVHLineSegmentVisitor::apply(BVHStaticGeometry& node) +{ + if (!intersects(_lineSegment, node.getBoundingSphere())) + return; + node.traverse(*this); +} + +void +BVHLineSegmentVisitor::apply(const BVHStaticBinary& node, + const BVHStaticData& data) +{ + if (!intersects(SGLineSegmentf(_lineSegment), node.getBoundingBox())) + return; + + // The first box to enter is the one the startpoint is in. + // this increases the probability, that on exit of that box we do not + // even need to walk the other one, since the line segment is + // then already short enough to not intersect the other one anymore. + node.traverse(*this, data, _lineSegment.getStart()); +} + +void +BVHLineSegmentVisitor::apply(const BVHStaticLeaf& node, + const BVHStaticData& data) +{ +} + +void +BVHLineSegmentVisitor::apply(const BVHStaticTriangle& triangle, + const BVHStaticData& data) +{ + SGTrianglef tri = triangle.getTriangle(data); + SGVec3f point; + if (!intersects(point, tri, SGLineSegmentf(_lineSegment), 1e-4f)) + return; + setLineSegmentEnd(SGVec3d(point)); + _normal = SGVec3d(tri.getNormal()); + _linearVelocity = SGVec3d::zeros(); + _angularVelocity = SGVec3d::zeros(); + _material = data.getMaterial(triangle.getMaterialIndex()); + _haveHit = true; +} + + +} diff --git a/simgear/scene/bvh/BVHLineSegmentVisitor.hxx b/simgear/scene/bvh/BVHLineSegmentVisitor.hxx new file mode 100644 index 00000000..aec9c081 --- /dev/null +++ b/simgear/scene/bvh/BVHLineSegmentVisitor.hxx @@ -0,0 +1,94 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHLineSegmentVisitor_hxx +#define BVHLineSegmentVisitor_hxx + +#include +#include +#include + +#include "BVHVisitor.hxx" + +namespace simgear { + +class BVHLineSegmentVisitor : public BVHVisitor { +public: + BVHLineSegmentVisitor(const SGLineSegmentd& lineSegment, + const double& t = 0) : + _lineSegment(lineSegment), + _time(t), + _material(0), + _haveHit(false) + { } + virtual ~BVHLineSegmentVisitor() + { } + + bool empty() const + { return !_haveHit; } + + const SGLineSegmentd& getLineSegment() const + { return _lineSegment; } + + SGVec3d getPoint() const + { return _lineSegment.getEnd(); } + const SGVec3d& getNormal() const + { return _normal; } + const SGVec3d& getLinearVelocity() const + { return _linearVelocity; } + const SGVec3d& getAngularVelocity() const + { return _angularVelocity; } + const SGMaterial* getMaterial() const + { return _material; } + + virtual void apply(BVHGroup& group); + virtual void apply(BVHTransform& transform); + virtual void apply(BVHMotionTransform& transform); + virtual void apply(BVHLineGeometry&); + virtual void apply(BVHStaticGeometry& node); + + virtual void apply(const BVHStaticBinary&, const BVHStaticData&); + virtual void apply(const BVHStaticLeaf&, const BVHStaticData&); + virtual void apply(const BVHStaticTriangle&, const BVHStaticData&); + +protected: + bool setLineSegmentEnd(const SGVec3d& end) + { + // Ok, you need to make sure that the new end is in the previous + // direction and that the line segment is not enlarged by that call. +#ifndef _NDEBUG + // FIXME insert code to check this... +#endif + _lineSegment.set(_lineSegment.getStart(), end); + } + +private: + SGLineSegmentd _lineSegment; + double _time; + + // belongs in a derived class + SGVec3d _normal; + SGVec3d _linearVelocity; + SGVec3d _angularVelocity; + const SGMaterial* _material; + + bool _haveHit; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHMotionTransform.cxx b/simgear/scene/bvh/BVHMotionTransform.cxx new file mode 100644 index 00000000..d97b66f1 --- /dev/null +++ b/simgear/scene/bvh/BVHMotionTransform.cxx @@ -0,0 +1,111 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHMotionTransform.hxx" + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" + +namespace simgear { + +BVHMotionTransform::BVHMotionTransform() : + _toWorldReference(SGMatrixd::unit()), + _toLocalReference(SGMatrixd::unit()), + _toWorldAmplification(1), + _toLocalAmplification(1), + _linearVelocity(0, 0, 0), + _angularVelocity(0, 0, 0), + _referenceTime(0), + _endTime(0) +{ +} + +BVHMotionTransform::~BVHMotionTransform() +{ +} + +void +BVHMotionTransform::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +void +BVHMotionTransform::setTransform(const BVHMotionTransform& transform) +{ + _toWorldReference = transform._toWorldReference; + _toLocalReference = transform._toLocalReference; + _toWorldAmplification = transform._toWorldAmplification; + _toLocalAmplification = transform._toLocalAmplification; + _linearVelocity = transform._linearVelocity; + _angularVelocity = transform._angularVelocity; + _referenceTime = transform._referenceTime; + _endTime = transform._endTime; + invalidateParentBound(); +} + +void +BVHMotionTransform::setToWorldTransform(const SGMatrixd& transform) +{ + _toWorldReference = transform; + invert(_toLocalReference, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +void +BVHMotionTransform::setToLocalTransform(const SGMatrixd& transform) +{ + _toLocalReference = transform; + invert(_toWorldReference, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +SGSphered +BVHMotionTransform::computeBoundingSphere() const +{ + SGSphered sphere(BVHGroup::computeBoundingSphere()); + if (sphere.empty()) + return sphere; + SGVec3d centerStart = _toWorldReference.xformPt(sphere.getCenter()); + SGMatrixd toWorldEnd = getToWorldTransform(_endTime); + SGVec3d centerEnd = toWorldEnd.xformPt(sphere.getCenter()); + double rad = 0.5*length(centerStart - centerEnd) + sphere.getRadius(); + rad *= _toWorldAmplification; + return SGSphered(0.5*(centerStart + centerEnd), rad); +} + +void +BVHMotionTransform::updateAmplificationFactors() +{ + // Hmm, this is just a hint, true? + // But anyway, almost all transforms in a scenegraph will + // have them equal to 1 ... + double r = norm(_toWorldReference.xformVec(SGVec3d(1, 0, 0))); + r = std::max(r, norm(_toWorldReference.xformVec(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(_toWorldReference.xformVec(SGVec3d(0, 0, 1)))); + _toWorldAmplification = r; + + r = norm(_toLocalReference.xformVec(SGVec3d(1, 0, 0))); + r = std::max(r, norm(_toLocalReference.xformVec(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(_toLocalReference.xformVec(SGVec3d(0, 0, 1)))); + _toLocalAmplification = r; +} + +} diff --git a/simgear/scene/bvh/BVHMotionTransform.hxx b/simgear/scene/bvh/BVHMotionTransform.hxx new file mode 100644 index 00000000..6e51e7ee --- /dev/null +++ b/simgear/scene/bvh/BVHMotionTransform.hxx @@ -0,0 +1,113 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHMotionTransform_hxx +#define BVHMotionTransform_hxx + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" + +namespace simgear { + +class BVHMotionTransform : public BVHGroup { +public: + BVHMotionTransform(); + virtual ~BVHMotionTransform(); + + virtual void accept(BVHVisitor& visitor); + + void setTransform(const BVHMotionTransform& transform); + void setToWorldTransform(const SGMatrixd& transform); + void setToLocalTransform(const SGMatrixd& transform); + + void setLinearVelocity(const SGVec3d& linearVelocity) + { _linearVelocity = linearVelocity; } + const SGVec3d& getLinearVelocity() const + { return _linearVelocity; } + + void setAngularVelocity(const SGVec3d& angularVelocity) + { _angularVelocity = angularVelocity; } + const SGVec3d& getAngularVelocity() const + { return _angularVelocity; } + + void setReferenceTime(const double& referenceTime) + { _referenceTime = referenceTime; } + const double& getReferenceTime() const + { return _referenceTime; } + + void setEndTime(const double& endTime) + { _endTime = endTime; } + const double& getEndTime() const + { return _endTime; } + + SGMatrixd getToWorldTransform(const double& t) const + { + double dt = t - _referenceTime; + if (0 == dt) + return _toWorldReference; + SGMatrixd matrix(_toWorldReference); + matrix.postMultRotate(SGQuatd::fromAngleAxis(dt*_angularVelocity)); + matrix.postMultTranslate(dt*_linearVelocity); + return matrix; + } + SGMatrixd getToLocalTransform(const double& t) const + { + double dt = _referenceTime - t; + if (0 == dt) + return _toLocalReference; + SGMatrixd matrix(_toLocalReference); + matrix.preMultRotate(SGQuatd::fromAngleAxis(dt*_angularVelocity)); + matrix.preMultTranslate(dt*_linearVelocity); + return matrix; + } + + const SGMatrixd& getToWorldReferenceTransform() const + { return _toWorldReference; } + const SGMatrixd& getToLocalReferenceTransform() const + { return _toLocalReference; } + + SGVec3d getLinearVelocityAt(const SGVec3d& reference) const + { return _linearVelocity + cross(_angularVelocity, reference); } + + SGSphered sphereToLocal(const SGSphered& sphere, const double& t) const + { + SGMatrixd matrix = getToLocalTransform(t); + SGVec3d center = matrix.xformPt(sphere.getCenter()); + double radius = _toLocalAmplification*sphere.getRadius(); + return SGSphered(center, radius); + } + +private: + virtual SGSphered computeBoundingSphere() const; + void updateAmplificationFactors(); + + SGMatrixd _toWorldReference; + SGMatrixd _toLocalReference; + double _toWorldAmplification; + double _toLocalAmplification; + + SGVec3d _linearVelocity; + SGVec3d _angularVelocity; + + double _referenceTime; + double _endTime; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHNode.cxx b/simgear/scene/bvh/BVHNode.cxx new file mode 100644 index 00000000..5d8f39f3 --- /dev/null +++ b/simgear/scene/bvh/BVHNode.cxx @@ -0,0 +1,72 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHNode.hxx" + +#include +#include + +namespace simgear { + +BVHNode::BVHNode() : + _dirtyBoundingSphere(true) +{ +} + +BVHNode::~BVHNode() +{ +} + +void +BVHNode::addParent(BVHNode* parent) +{ + // should not happen, but be paranoid ... + ParentList::iterator i; + i = std::find(_parents.begin(), _parents.end(), parent); + if (i != _parents.end()) + return; + // add to the parents list ... + _parents.push_back(parent); +} + +void +BVHNode::removeParent(BVHNode* parent) +{ + ParentList::iterator i; + i = std::find(_parents.begin(), _parents.end(), parent); + if (i == _parents.end()) + return; + _parents.erase(i); +} + +void +BVHNode::invalidateParentBound() +{ + for (ParentList::iterator i = _parents.begin(); i != _parents.end(); ++i) + (*i)->invalidateBound(); +} + +void +BVHNode::invalidateBound() +{ + if (_dirtyBoundingSphere) + return; + invalidateParentBound(); + _dirtyBoundingSphere = true; +} + +} diff --git a/simgear/scene/bvh/BVHNode.hxx b/simgear/scene/bvh/BVHNode.hxx new file mode 100644 index 00000000..3bdce72f --- /dev/null +++ b/simgear/scene/bvh/BVHNode.hxx @@ -0,0 +1,67 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHNode_hxx +#define BVHNode_hxx + +#include +#include +#include + +namespace simgear { + +class BVHGroup; +class BVHVisitor; + +// Base for the tree nodes +class BVHNode : public SGReferenced { +public: + BVHNode(); + virtual ~BVHNode(); + + // visitors ... + virtual void accept(BVHVisitor& visitor) = 0; + + const SGSphered& getBoundingSphere() const + { + if (_dirtyBoundingSphere) { + _boundingSphere = computeBoundingSphere(); + _dirtyBoundingSphere = false; + } + return _boundingSphere; + } + virtual SGSphered computeBoundingSphere() const = 0; + +protected: + friend class BVHGroup; + void addParent(BVHNode* parent); + void removeParent(BVHNode* parent); + + void invalidateParentBound(); + virtual void invalidateBound(); + +private: + mutable bool _dirtyBoundingSphere; + mutable SGSphered _boundingSphere; + + typedef std::vector ParentList; + ParentList _parents; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticBinary.cxx b/simgear/scene/bvh/BVHStaticBinary.cxx new file mode 100644 index 00000000..d98a35e0 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticBinary.cxx @@ -0,0 +1,45 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHStaticBinary.hxx" + +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHStaticBinary::BVHStaticBinary(unsigned splitAxis, + const BVHStaticNode* leftChild, + const BVHStaticNode* rightChild, + const SGBoxf& boundingBox) : + _splitAxis(splitAxis), + _leftChild(leftChild), + _rightChild(rightChild), + _boundingBox(boundingBox) +{ +} + +BVHStaticBinary::~BVHStaticBinary() +{ +} + +void +BVHStaticBinary::accept(BVHVisitor& visitor, const BVHStaticData& data) const +{ + visitor.apply(*this, data); +} + +} diff --git a/simgear/scene/bvh/BVHStaticBinary.hxx b/simgear/scene/bvh/BVHStaticBinary.hxx new file mode 100644 index 00000000..05b8aa3b --- /dev/null +++ b/simgear/scene/bvh/BVHStaticBinary.hxx @@ -0,0 +1,78 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticBinary_hxx +#define BVHStaticBinary_hxx + +#include +#include +#include "BVHStaticNode.hxx" + +namespace simgear { + +class BVHStaticBinary : public BVHStaticNode { +public: + BVHStaticBinary(unsigned splitAxis, const BVHStaticNode* leftChild, + const BVHStaticNode* rightChild, const SGBoxf& box); + virtual ~BVHStaticBinary(); + virtual void accept(BVHVisitor& visitor, const BVHStaticData& data) const; + + void traverse(BVHVisitor& visitor, const BVHStaticData& data) const + { + _leftChild->accept(visitor, data); + _rightChild->accept(visitor, data); + } + + // Traverse call that first enters the child node that is potentially closer + // to the given point than the other. + template + void traverse(BVHVisitor& visitor, const BVHStaticData& data, + const SGVec3& pt) const + { + float center = 0.5f*(_boundingBox.getMin()[_splitAxis] + + _boundingBox.getMax()[_splitAxis]); + if (pt[_splitAxis] < center) { + _leftChild->accept(visitor, data); + _rightChild->accept(visitor, data); + } else { + _rightChild->accept(visitor, data); + _leftChild->accept(visitor, data); + } + } + + unsigned getSplitAxis() const + { return _splitAxis; } + + const BVHStaticNode* getLeftChild() const + { return _leftChild; } + const BVHStaticNode* getRightChild() const + { return _rightChild; } + + const SGBoxf& getBoundingBox() const + { return _boundingBox; } + +private: + // Note the order of the members, this is to avoid padding + unsigned _splitAxis; + SGSharedPtr _leftChild; + SGSharedPtr _rightChild; + SGBoxf _boundingBox; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticData.hxx b/simgear/scene/bvh/BVHStaticData.hxx new file mode 100644 index 00000000..27bacef2 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticData.hxx @@ -0,0 +1,55 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticData_hxx +#define BVHStaticData_hxx + +#include +#include +#include +#include + +/// FIXME, the SGMaterial class is too much tied to the scenegraph aspects of +/// the materials. Use some class more decribing the +/// nature of the surface we live on ... +class SGMaterial; + +namespace simgear { + +class BVHStaticData : public SGReferenced { +public: + virtual ~BVHStaticData() {} + + unsigned addVertex(const SGVec3f& vertex) + { _vertices.push_back(vertex); return _vertices.size() - 1; } + const SGVec3f& getVertex(unsigned i) const + { return _vertices[i]; } + + + unsigned addMaterial(const SGMaterial* material) + { _materials.push_back(material); return _materials.size() - 1; } + const SGMaterial* getMaterial(unsigned i) const + { if (_materials.size() <= i) return 0; return _materials[i]; } + +private: + std::vector _vertices; + std::vector _materials; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticGeometry.cxx b/simgear/scene/bvh/BVHStaticGeometry.cxx new file mode 100644 index 00000000..a8479565 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticGeometry.cxx @@ -0,0 +1,51 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHStaticGeometry.hxx" + +#include "BVHBoundingBoxVisitor.hxx" + +namespace simgear { + +BVHStaticGeometry::BVHStaticGeometry(const BVHStaticNode* staticNode, + const BVHStaticData* staticData) : + _staticNode(staticNode), + _staticData(staticData) +{ +} + +BVHStaticGeometry::~BVHStaticGeometry() +{ +} + +void +BVHStaticGeometry::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +SGSphered +BVHStaticGeometry::computeBoundingSphere() const +{ + BVHBoundingBoxVisitor bbv; + _staticNode->accept(bbv, *_staticData); + SGSphered sphere; + sphere.expandBy(SGBoxd(bbv.getBox())); + return sphere; +} + +} diff --git a/simgear/scene/bvh/BVHStaticGeometry.hxx b/simgear/scene/bvh/BVHStaticGeometry.hxx new file mode 100644 index 00000000..693d4ff8 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticGeometry.hxx @@ -0,0 +1,56 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticGeometry_hxx +#define BVHStaticGeometry_hxx + +#include +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHStaticData.hxx" +#include "BVHStaticNode.hxx" + +namespace simgear { + +class BVHStaticGeometry : public BVHNode { +public: + BVHStaticGeometry(const BVHStaticNode* staticNode, + const BVHStaticData* staticData); + virtual ~BVHStaticGeometry(); + + virtual void accept(BVHVisitor& visitor); + + void traverse(BVHVisitor& visitor) const + { _staticNode->accept(visitor, *_staticData); } + + const BVHStaticData* getStaticData() const + { return _staticData; } + const BVHStaticNode* getStaticNode() const + { return _staticNode; } + + virtual SGSphered computeBoundingSphere() const; + +private: + SGSharedPtr _staticNode; + SGSharedPtr _staticData; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticGeometryBuilder.hxx b/simgear/scene/bvh/BVHStaticGeometryBuilder.hxx new file mode 100644 index 00000000..88bfd8e4 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticGeometryBuilder.hxx @@ -0,0 +1,215 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticGeometryBuilder_hxx +#define BVHStaticGeometryBuilder_hxx + +#include +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" +#include "BVHStaticGeometry.hxx" + +namespace simgear { + +class BVHStaticGeometryBuilder : public SGReferenced { +public: + BVHStaticGeometryBuilder() : + _staticData(new BVHStaticData), + _currentMaterial(0), + _currentMaterialIndex(~0u) + { } + virtual ~BVHStaticGeometryBuilder() + { } + + struct LeafRef { + LeafRef(const BVHStaticLeaf* leaf, const BVHStaticData& data) : + _leaf(leaf), + _box(_leaf->computeBoundingBox(data)), + _center(_leaf->computeCenter(data)) + { } + SGSharedPtr _leaf; + SGBoxf _box; + SGVec3f _center; + }; + typedef std::list LeafRefList; + + struct LeafRefLess : public std::binary_function { + LeafRefLess(unsigned sortAxis) : _sortAxis(sortAxis) {} + bool operator()(const LeafRef& x, const LeafRef& y) + { return x._center[_sortAxis] < y._center[_sortAxis]; } + unsigned _sortAxis; + }; + + SGSharedPtr _staticData; + LeafRefList _leafRefList; + + typedef std::map VertexMap; + VertexMap _vertexMap; + + void setCurrentMaterial(const SGMaterial* material) + { + _currentMaterial = material; + _currentMaterialIndex = addMaterial(material); + } + const SGMaterial* getCurrentMaterial() const + { + return _currentMaterial; + } + unsigned addMaterial(const SGMaterial* material) + { + MaterialMap::const_iterator i = _materialMap.find(material); + if (i != _materialMap.end()) + return i->second; + unsigned index = _staticData->addMaterial(material); + _materialMap[material] = index; + return index; + } + + typedef std::map MaterialMap; + MaterialMap _materialMap; + const SGMaterial* _currentMaterial; + unsigned _currentMaterialIndex; + + void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3) + { + unsigned indices[3] = { addVertex(v1), addVertex(v2), addVertex(v3) }; + BVHStaticTriangle* staticTriangle; + staticTriangle = new BVHStaticTriangle(_currentMaterialIndex, indices); + _leafRefList.push_back(LeafRef(staticTriangle, *_staticData)); + } + unsigned addVertex(const SGVec3f& v) + { + VertexMap::const_iterator i = _vertexMap.find(v); + if (i != _vertexMap.end()) + return i->second; + unsigned index = _staticData->addVertex(v); + _vertexMap[v] = index; + return index; + } + + BVHStaticGeometry* buildTree() + { + const BVHStaticNode* tree = buildTreeRecursive(_leafRefList); + if (!tree) + return 0; + return new BVHStaticGeometry(tree, _staticData); + } + +private: + static void + centerSplitLeafs(unsigned splitAxis, const double& splitValue, + LeafRefList& leafs, LeafRefList split[2]) + { + while (!leafs.empty()) { + if (leafs.front()._center[splitAxis] < splitValue) { + split[0].splice(split[0].begin(), leafs, leafs.begin()); + } else { + split[1].splice(split[1].begin(), leafs, leafs.begin()); + } + } + } + + static void + equalSplitLeafs(unsigned splitAxis, LeafRefList& leafs, + LeafRefList split[2]) + { + leafs.sort(LeafRefLess(splitAxis)); + while (true) { + if (leafs.empty()) + break; + split[0].splice(split[0].begin(), leafs, leafs.begin()); + + if (leafs.empty()) + break; + split[1].splice(split[1].begin(), leafs, --leafs.end()); + } + } + + static const BVHStaticNode* buildTreeRecursive(LeafRefList& leafs) + { + // recursion termination + if (leafs.empty()) + return 0; + // FIXME size is O(n)!!! + // if (leafs.size() == 1) + if (++leafs.begin() == leafs.end()) + return leafs.front()._leaf; + + SGBoxf box; + for (LeafRefList::const_iterator i = leafs.begin(); + i != leafs.end(); ++i) + box.expandBy(i->_box); + + // // FIXME ... + // if (length(box.getSize()) < 1) + // return new BVHBox(box); + + if (box.empty()) + return 0; + + unsigned splitAxis = box.getBroadestAxis(); + LeafRefList splitLeafs[2]; + double splitValue = box.getCenter()[splitAxis]; + centerSplitLeafs(splitAxis, splitValue, leafs, splitLeafs); + + if (splitLeafs[0].empty() || splitLeafs[1].empty()) { + for (unsigned i = 0; i < 3 ; ++i) { + if (i == splitAxis) + continue; + + leafs.swap(splitLeafs[0]); + leafs.splice(leafs.begin(), splitLeafs[1]); + splitValue = box.getCenter()[i]; + centerSplitLeafs(i, splitValue, leafs, splitLeafs); + + if (!splitLeafs[0].empty() && !splitLeafs[1].empty()) { + splitAxis = i; + break; + } + } + } + if (splitLeafs[0].empty() || splitLeafs[1].empty()) { + leafs.swap(splitLeafs[0]); + leafs.splice(leafs.begin(), splitLeafs[1]); + equalSplitLeafs(splitAxis, leafs, splitLeafs); + } + + const BVHStaticNode* child0 = buildTreeRecursive(splitLeafs[0]); + const BVHStaticNode* child1 = buildTreeRecursive(splitLeafs[1]); + if (!child0) + return child1; + if (!child1) + return child0; + + return new BVHStaticBinary(splitAxis, child0, child1, box); + } +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticLeaf.cxx b/simgear/scene/bvh/BVHStaticLeaf.cxx new file mode 100644 index 00000000..67137530 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticLeaf.cxx @@ -0,0 +1,33 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHStaticLeaf.hxx" +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHStaticLeaf::~BVHStaticLeaf() +{ +} + +void +BVHStaticLeaf::accept(BVHVisitor& visitor, const BVHStaticData& data) const +{ + visitor.apply(*this, data); +} + +} diff --git a/simgear/scene/bvh/BVHStaticLeaf.hxx b/simgear/scene/bvh/BVHStaticLeaf.hxx new file mode 100644 index 00000000..3a7682f7 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticLeaf.hxx @@ -0,0 +1,38 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticLeaf_hxx +#define BVHStaticLeaf_hxx + +#include +#include "BVHStaticNode.hxx" + +namespace simgear { + +class BVHStaticLeaf : public BVHStaticNode { +public: + virtual ~BVHStaticLeaf(); + + virtual void accept(BVHVisitor& visitor, const BVHStaticData& data) const; + + virtual SGBoxf computeBoundingBox(const BVHStaticData&) const = 0; + virtual SGVec3f computeCenter(const BVHStaticData&) const = 0; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticNode.cxx b/simgear/scene/bvh/BVHStaticNode.cxx new file mode 100644 index 00000000..4ab67c3f --- /dev/null +++ b/simgear/scene/bvh/BVHStaticNode.cxx @@ -0,0 +1,26 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHStaticNode.hxx" + +namespace simgear { + +BVHStaticNode::~BVHStaticNode() +{ +} + +} diff --git a/simgear/scene/bvh/BVHStaticNode.hxx b/simgear/scene/bvh/BVHStaticNode.hxx new file mode 100644 index 00000000..8134599a --- /dev/null +++ b/simgear/scene/bvh/BVHStaticNode.hxx @@ -0,0 +1,37 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticNode_hxx +#define BVHStaticNode_hxx + +#include + +namespace simgear { + +class BVHStaticData; +class BVHVisitor; + +class BVHStaticNode : public SGReferenced { +public: + virtual ~BVHStaticNode(); + + virtual void accept(BVHVisitor&, const BVHStaticData&) const = 0; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticTriangle.cxx b/simgear/scene/bvh/BVHStaticTriangle.cxx new file mode 100644 index 00000000..53572060 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticTriangle.cxx @@ -0,0 +1,58 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHStaticTriangle.hxx" + +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHStaticTriangle::BVHStaticTriangle(unsigned material, + const unsigned indices[3]) : + _material(material) +{ + for (unsigned i = 0; i < 3; ++i) + _indices[i] = indices[i]; +} + +BVHStaticTriangle::~BVHStaticTriangle() +{ +} + +void +BVHStaticTriangle::accept(BVHVisitor& visitor, const BVHStaticData& data) const +{ + visitor.apply(*this, data); +} + +SGBoxf +BVHStaticTriangle::computeBoundingBox(const BVHStaticData& data) const +{ + SGBoxf box; + box.expandBy(data.getVertex(_indices[0])); + box.expandBy(data.getVertex(_indices[1])); + box.expandBy(data.getVertex(_indices[2])); + return box; +} + +SGVec3f +BVHStaticTriangle::computeCenter(const BVHStaticData& data) const +{ + return getTriangle(data).getCenter(); +} + +} diff --git a/simgear/scene/bvh/BVHStaticTriangle.hxx b/simgear/scene/bvh/BVHStaticTriangle.hxx new file mode 100644 index 00000000..79ff391f --- /dev/null +++ b/simgear/scene/bvh/BVHStaticTriangle.hxx @@ -0,0 +1,54 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHStaticTriangle_hxx +#define BVHStaticTriangle_hxx + +#include +#include "BVHStaticData.hxx" +#include "BVHStaticLeaf.hxx" + +namespace simgear { + +class BVHStaticTriangle : public BVHStaticLeaf { +public: + BVHStaticTriangle(unsigned material, const unsigned indices[3]); + virtual ~BVHStaticTriangle(); + + virtual void accept(BVHVisitor& visitor, const BVHStaticData& data) const; + + virtual SGBoxf computeBoundingBox(const BVHStaticData& data) const; + virtual SGVec3f computeCenter(const BVHStaticData& data) const; + + SGTrianglef getTriangle(const BVHStaticData& data) const + { + return SGTrianglef(data.getVertex(_indices[0]), + data.getVertex(_indices[1]), + data.getVertex(_indices[2])); + } + + unsigned getMaterialIndex() const + { return _material; } + +private: + unsigned _indices[3]; + unsigned _material; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHSubTreeCollector.cxx b/simgear/scene/bvh/BVHSubTreeCollector.cxx new file mode 100644 index 00000000..cc7596be --- /dev/null +++ b/simgear/scene/bvh/BVHSubTreeCollector.cxx @@ -0,0 +1,258 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHSubTreeCollector.hxx" + +#include + +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" +#include "BVHStaticGeometry.hxx" +#include "BVHBoundingBoxVisitor.hxx" + +namespace simgear { + +BVHSubTreeCollector::BVHSubTreeCollector(const SGSphered& sphere) : + _sphere(sphere) +{ +} + +BVHSubTreeCollector::~BVHSubTreeCollector() +{ +} + +void +BVHSubTreeCollector::apply(BVHGroup& group) +{ + if (!intersects(_sphere, group.getBoundingSphere())) + return; + + // The _nodeList content is somehow the 'return value' of the subtree. + // Set it to zero to see if we have something to collect down there. + NodeList parentNodeList; + pushNodeList(parentNodeList); + + group.traverse(*this); + + popNodeList(parentNodeList); +} + +void +BVHSubTreeCollector::apply(BVHTransform& transform) +{ + if (!intersects(_sphere, transform.getBoundingSphere())) + return; + + SGSphered sphere = _sphere; + _sphere = transform.sphereToLocal(sphere); + + NodeList parentNodeList; + pushNodeList(parentNodeList); + + transform.traverse(*this); + + if (haveChildren()) { + BVHTransform* currentBvTransform = new BVHTransform; + currentBvTransform->setTransform(transform); + popNodeList(parentNodeList, currentBvTransform); + } else { + popNodeList(parentNodeList); + } + + _sphere = sphere; +} + +void +BVHSubTreeCollector::apply(BVHMotionTransform& transform) +{ + if (!intersects(_sphere, transform.getBoundingSphere())) + return; + + SGSphered sphere = _sphere; + _sphere = transform.sphereToLocal(sphere, transform.getReferenceTime()); + _sphere.expandBy(transform.sphereToLocal(sphere, transform.getEndTime())); + + NodeList parentNodeList; + pushNodeList(parentNodeList); + + transform.traverse(*this); + + if (haveChildren()) { + BVHMotionTransform* currentBvTransform = new BVHMotionTransform; + currentBvTransform->setTransform(transform); + popNodeList(parentNodeList, currentBvTransform); + } else { + popNodeList(parentNodeList); + } + + _sphere = sphere; +} + +void +BVHSubTreeCollector::apply(BVHLineGeometry& lineSegment) +{ + if (!intersects(_sphere, lineSegment.getBoundingSphere())) + return; + addNode(&lineSegment); +} + +void +BVHSubTreeCollector::apply(BVHStaticGeometry& node) +{ + if (!intersects(_sphere, node.getBoundingSphere())) + return; + + assert(!_staticNode); + node.traverse(*this); + if (!_staticNode) + return; + + BVHStaticGeometry* staticTree; + staticTree = new BVHStaticGeometry(_staticNode, node.getStaticData()); + addNode(staticTree); + _staticNode = 0; +} + +void +BVHSubTreeCollector::apply(const BVHStaticBinary& node, + const BVHStaticData& data) +{ + assert(!_staticNode); + + if (!intersects(_sphere, node.getBoundingBox())) + return; + + SGVec3d corner(node.getBoundingBox().getFarestCorner(_sphere.getCenter())); + if (intersects(_sphere, corner)) { + // If the box is totally contained in the sphere, just take it all + _staticNode = &node; + + } else { + // We have still a chance to seperate something out, try it. + + node.getLeftChild()->accept(*this, data); + SGSharedPtr leftStaticNode = _staticNode; + _staticNode = 0; + node.getRightChild()->accept(*this, data); + SGSharedPtr rightStaticNode = _staticNode; + _staticNode = 0; + + if (leftStaticNode) { + if (rightStaticNode) { + BVHBoundingBoxVisitor bbv; + leftStaticNode->accept(bbv, data); + rightStaticNode->accept(bbv, data); + _staticNode + = new BVHStaticBinary(node.getSplitAxis(), leftStaticNode, + rightStaticNode, bbv.getBox()); + } else { + _staticNode = leftStaticNode; + } + } else { + if (rightStaticNode) { + _staticNode = rightStaticNode; + } else { + // Nothing to report to parents ... + } + } + } +} + +void +BVHSubTreeCollector::apply(const BVHStaticLeaf& node, + const BVHStaticData& data) +{ + if (!intersects(_sphere, node.computeBoundingBox(data))) + return; + _staticNode = &node; +} + +void +BVHSubTreeCollector::apply(const BVHStaticTriangle& node, + const BVHStaticData& data) +{ + if (!intersects(_sphere, node.computeBoundingBox(data))) + return; + _staticNode = &node; +} + +void +BVHSubTreeCollector::addNode(BVHNode* node) +{ + if (!node) + return; + if (!_nodeList.capacity()) + _nodeList.reserve(64); + _nodeList.push_back(node); +} + +void +BVHSubTreeCollector::popNodeList(NodeList& parentNodeList, BVHGroup* transform) +{ + // Only do something if we really have children + if (!_nodeList.empty()) { + NodeList::const_iterator i; + for (i = _nodeList.begin(); i != _nodeList.end(); ++i) + transform->addChild(*i); + parentNodeList.push_back(transform); + } + _nodeList.swap(parentNodeList); +} + +void +BVHSubTreeCollector::popNodeList(NodeList& parentNodeList) +{ + // Only do something if we really have children + if (!_nodeList.empty()) { + if (_nodeList.size() == 1) { + parentNodeList.push_back(_nodeList.front()); + } else { + BVHGroup* group = new BVHGroup; + NodeList::const_iterator i; + for (i = _nodeList.begin(); i != _nodeList.end(); ++i) + group->addChild(*i); + parentNodeList.push_back(group); + } + } + _nodeList.swap(parentNodeList); +} + +SGSharedPtr +BVHSubTreeCollector::getNode() const +{ + if (_nodeList.empty()) + return 0; + + if (_nodeList.size() == 1) + return _nodeList.front(); + + BVHGroup* group = new BVHGroup; + NodeList::const_iterator i; + for (i = _nodeList.begin(); i != _nodeList.end(); ++i) + group->addChild(*i); + return group; +} + +} diff --git a/simgear/scene/bvh/BVHSubTreeCollector.hxx b/simgear/scene/bvh/BVHSubTreeCollector.hxx new file mode 100644 index 00000000..b29d6274 --- /dev/null +++ b/simgear/scene/bvh/BVHSubTreeCollector.hxx @@ -0,0 +1,82 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHSubTreeCollector_hxx +#define BVHSubTreeCollector_hxx + +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHStaticNode.hxx" + +namespace simgear { + +/// Visitor to subcollect parts of an existing bounding volume tree. +/// Given a sphere, it takes those sub parts of the tree that intersect the +/// sphere. Transform nodes of any kind are preserved to be able to ask for +/// intersections a different times. The subcollected tree is kept as small as +/// possible as it does avoid having groups with single childs. +/// Also the BVHStaticGeometry parts are seached for subtrees that are outside +/// the sphere. + +class BVHSubTreeCollector : public BVHVisitor { +public: + typedef std::vector > NodeList; + + BVHSubTreeCollector(const SGSphered& sphere = SGSphered()); + virtual ~BVHSubTreeCollector(); + + virtual void apply(BVHGroup&); + virtual void apply(BVHTransform&); + virtual void apply(BVHMotionTransform&); + virtual void apply(BVHLineGeometry&); + virtual void apply(BVHStaticGeometry&); + + virtual void apply(const BVHStaticBinary&, const BVHStaticData&); + virtual void apply(const BVHStaticLeaf&, const BVHStaticData&); + virtual void apply(const BVHStaticTriangle&, const BVHStaticData&); + + void setSphere(const SGSphered& sphere) + { _sphere = sphere; } + const SGSphered& getSphere() const + { return _sphere; } + + bool haveChildren() const + { return !_nodeList.empty(); } + + void addNode(BVHNode* node); + + void pushNodeList(NodeList& parentNodeList) + { _nodeList.swap(parentNodeList); } + void popNodeList(NodeList& parentNodeList, BVHGroup* transform); + void popNodeList(NodeList& parentNodeList); + + SGSharedPtr getNode() const; + +protected: + NodeList _nodeList; + SGSharedPtr _staticNode; + +private: + SGSphered _sphere; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHTransform.cxx b/simgear/scene/bvh/BVHTransform.cxx new file mode 100644 index 00000000..27b615ad --- /dev/null +++ b/simgear/scene/bvh/BVHTransform.cxx @@ -0,0 +1,95 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "BVHTransform.hxx" + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" + +namespace simgear { + +BVHTransform::BVHTransform() : + _toWorld(SGMatrixd::unit()), + _toLocal(SGMatrixd::unit()), + _toWorldAmplification(1), + _toLocalAmplification(1) +{ +} + +BVHTransform::~BVHTransform() +{ +} + +void +BVHTransform::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +void +BVHTransform::setTransform(const BVHTransform& transform) +{ + _toWorld = transform._toWorld; + _toLocal = transform._toLocal; + _toWorldAmplification = transform._toWorldAmplification; + _toLocalAmplification = transform._toLocalAmplification; + invalidateParentBound(); +} + +void +BVHTransform::setToWorldTransform(const SGMatrixd& transform) +{ + _toWorld = transform; + invert(_toLocal, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +void +BVHTransform::setToLocalTransform(const SGMatrixd& transform) +{ + _toLocal = transform; + invert(_toWorld, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +SGSphered +BVHTransform::computeBoundingSphere() const +{ + return sphereToWorld(BVHGroup::computeBoundingSphere()); +} + +void +BVHTransform::updateAmplificationFactors() +{ + // Hmm, this is just a hint, true? + // But anyway, almost all transforms in a scenegraph will + // have them equal to 1 ... + double r = norm(vecToWorld(SGVec3d(1, 0, 0))); + r = std::max(r, norm(vecToWorld(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(vecToWorld(SGVec3d(0, 0, 1)))); + _toWorldAmplification = r; + + r = norm(vecToLocal(SGVec3d(1, 0, 0))); + r = std::max(r, norm(vecToLocal(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(vecToLocal(SGVec3d(0, 0, 1)))); + _toLocalAmplification = r; +} + +} diff --git a/simgear/scene/bvh/BVHTransform.hxx b/simgear/scene/bvh/BVHTransform.hxx new file mode 100644 index 00000000..d8b5096c --- /dev/null +++ b/simgear/scene/bvh/BVHTransform.hxx @@ -0,0 +1,82 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHTransform_hxx +#define BVHTransform_hxx + +#include "BVHGroup.hxx" + +namespace simgear { + +class BVHTransform : public BVHGroup { +public: + BVHTransform(); + virtual ~BVHTransform(); + + virtual void accept(BVHVisitor& visitor); + + void setTransform(const BVHTransform& transform); + + void setToWorldTransform(const SGMatrixd& transform); + const SGMatrixd& getToWorldTransform() const + { return _toWorld; } + + void setToLocalTransform(const SGMatrixd& transform); + const SGMatrixd& getToLocalTransform() const + { return _toLocal; } + + SGVec3d ptToWorld(const SGVec3d& point) const + { return _toWorld.xformPt(point); } + SGVec3d ptToLocal(const SGVec3d& point) const + { return _toLocal.xformPt(point); } + + SGVec3d vecToWorld(const SGVec3d& vec) const + { return _toWorld.xformVec(vec); } + SGVec3d vecToLocal(const SGVec3d& vec) const + { return _toLocal.xformVec(vec); } + + SGLineSegmentd lineSegmentToWorld(const SGLineSegmentd& lineSeg) const + { return lineSeg.transform(_toWorld); } + SGLineSegmentd lineSegmentToLocal(const SGLineSegmentd& lineSeg) const + { return lineSeg.transform(_toLocal); } + + SGSphered sphereToWorld(const SGSphered& sphere) const + { + SGVec3d center = ptToWorld(sphere.getCenter()); + double radius = _toWorldAmplification*sphere.getRadius(); + return SGSphered(center, radius); + } + SGSphered sphereToLocal(const SGSphered& sphere) const + { + SGVec3d center = ptToLocal(sphere.getCenter()); + double radius = _toLocalAmplification*sphere.getRadius(); + return SGSphered(center, radius); + } + +private: + virtual SGSphered computeBoundingSphere() const; + void updateAmplificationFactors(); + + SGMatrixd _toWorld; + SGMatrixd _toLocal; + double _toWorldAmplification; + double _toLocalAmplification; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHVisitor.hxx b/simgear/scene/bvh/BVHVisitor.hxx new file mode 100644 index 00000000..058cf27c --- /dev/null +++ b/simgear/scene/bvh/BVHVisitor.hxx @@ -0,0 +1,58 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef BVHVisitor_hxx +#define BVHVisitor_hxx + +namespace simgear { + +class BVHStaticData; + +class BVHGroup; +class BVHTransform; +class BVHMotionTransform; +class BVHStaticGeometry; +class BVHLineGeometry; + +class BVHStaticBinary; +class BVHStaticLeaf; +class BVHStaticTriangle; + +class BVHVisitor { +public: + // The magnitudes of pure virtuals is because of the fact that this chaining + // just takes needless runtime. This declaration should force the user of + // this classes to implement a common functionality that should be called + // from each apropriate apply method directly. + virtual ~BVHVisitor() {} + + // High level nodes to handle + virtual void apply(BVHGroup&) = 0; + virtual void apply(BVHTransform&) = 0; + virtual void apply(BVHMotionTransform&) = 0; + virtual void apply(BVHLineGeometry&) = 0; + virtual void apply(BVHStaticGeometry&) = 0; + + // Static tree nodes to handle + virtual void apply(const BVHStaticBinary&, const BVHStaticData&) = 0; + virtual void apply(const BVHStaticLeaf&, const BVHStaticData&) = 0; + virtual void apply(const BVHStaticTriangle&, const BVHStaticData&) = 0; +}; + +} + +#endif diff --git a/simgear/scene/bvh/Makefile.am b/simgear/scene/bvh/Makefile.am new file mode 100644 index 00000000..0b1be985 --- /dev/null +++ b/simgear/scene/bvh/Makefile.am @@ -0,0 +1,46 @@ +includedir = @includedir@/scene/bvh + +check_PROGRAMS = bvhtest +TESTS = $(check_PROGRAMS) + +bvhtest_SOURCES = bvhtest.cxx +bvhtest_LDADD = libsgbvh.a -lsgstructure -lsgmath $(base_LIBS) + +lib_LIBRARIES = libsgbvh.a + +noinst_HEADERS = + +include_HEADERS = \ + BVHBoundingBoxVisitor.hxx \ + BVHDebugCollectVisitor.hxx \ + BVHGroup.hxx \ + BVHLineSegmentVisitor.hxx \ + BVHLineGeometry.hxx \ + BVHMotionTransform.hxx \ + BVHNode.hxx \ + BVHStaticBinary.hxx \ + BVHStaticData.hxx \ + BVHStaticGeometry.hxx \ + BVHStaticGeometryBuilder.hxx \ + BVHStaticLeaf.hxx \ + BVHStaticNode.hxx \ + BVHStaticTriangle.hxx \ + BVHSubTreeCollector.hxx \ + BVHTransform.hxx \ + BVHVisitor.hxx + +libsgbvh_a_SOURCES = \ + BVHGroup.cxx \ + BVHLineGeometry.cxx \ + BVHLineSegmentVisitor.cxx \ + BVHMotionTransform.cxx \ + BVHNode.cxx \ + BVHStaticBinary.cxx \ + BVHStaticGeometry.cxx \ + BVHStaticLeaf.cxx \ + BVHStaticNode.cxx \ + BVHStaticTriangle.cxx \ + BVHSubTreeCollector.cxx \ + BVHTransform.cxx + +INCLUDES = -I$(top_srcdir) diff --git a/simgear/scene/bvh/bvhtest.cxx b/simgear/scene/bvh/bvhtest.cxx new file mode 100644 index 00000000..797299cb --- /dev/null +++ b/simgear/scene/bvh/bvhtest.cxx @@ -0,0 +1,118 @@ +// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include +#include + +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" +#include "BVHStaticGeometry.hxx" + +#include "BVHBoundingBoxVisitor.hxx" +#include "BVHSubTreeCollector.hxx" +#include "BVHLineSegmentVisitor.hxx" + +using namespace simgear; + +BVHNode* +buildSingleTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3) +{ + BVHStaticData* staticData = new BVHStaticData; + unsigned indices[3] = { + staticData->addVertex(v1), + staticData->addVertex(v2), + staticData->addVertex(v3) + }; + BVHStaticTriangle* staticTriangle = new BVHStaticTriangle(~0u, indices); + return new BVHStaticGeometry(staticTriangle, staticData); +} + +bool +testLineIntersections() +{ + SGVec3f v1(-1, -1, 0); + SGVec3f v2(1, -1, 0); + SGVec3f v3(-1, 1, 0); + SGSharedPtr node = buildSingleTriangle(v1, v2, v3); + + SGLineSegmentd lineSegment(SGVec3d(0, 0, -1), SGVec3d(0, 0, 1)); + { + BVHLineSegmentVisitor lineSegmentVisitor(lineSegment); + node->accept(lineSegmentVisitor); + if (lineSegmentVisitor.empty()) + return false; + if (!equivalent(lineSegmentVisitor.getPoint(), SGVec3d(0, 0, 0))) + return false; + } + + SGVec3d position(1000, 1000, 1000); + SGMatrixd matrix(position); + SGSharedPtr transform1 = new BVHTransform; + transform1->setToWorldTransform(matrix); + transform1->addChild(node); + + SGSharedPtr transform2 = new BVHTransform; + transform2->setToLocalTransform(matrix); + transform2->addChild(transform1); + + { + BVHLineSegmentVisitor lineSegmentVisitor(lineSegment); + transform2->accept(lineSegmentVisitor); + if (lineSegmentVisitor.empty()) + return false; + if (!equivalent(lineSegmentVisitor.getPoint(), SGVec3d(0, 0, 0))) + return false; + } + + SGSharedPtr transform3 = new BVHMotionTransform; + transform3->setLinearVelocity(SGVec3d(0, 0, 1)); + transform3->setAngularVelocity(SGVec3d(1, 0, 0)); + transform3->addChild(node); + + { + BVHLineSegmentVisitor lineSegmentVisitor(lineSegment, 0); + transform3->accept(lineSegmentVisitor); + if (lineSegmentVisitor.empty()) + return false; + if (!equivalent(lineSegmentVisitor.getPoint(), SGVec3d(0, 0, 0))) + return false; + if (!equivalent(lineSegmentVisitor.getLinearVelocity(), + SGVec3d(0, 1, 1))) + return false; + if (!equivalent(lineSegmentVisitor.getAngularVelocity(), + SGVec3d(1, 0, 0))) + return false; + } + + return true; +} + +int +main(int argc, char** argv) +{ + if (!testLineIntersections()) + return EXIT_FAILURE; + return EXIT_SUCCESS; +}