diff --git a/examples/osgkdtree/osgkdtree.cpp b/examples/osgkdtree/osgkdtree.cpp index 50ce6efdd..2a19e88ea 100644 --- a/examples/osgkdtree/osgkdtree.cpp +++ b/examples/osgkdtree/osgkdtree.cpp @@ -37,9 +37,12 @@ #include #include +#include + #include "fixeddivision.h" #include "variabledivision.h" +#include int main(int argc, char **argv) { @@ -55,6 +58,8 @@ int main(int argc, char **argv) while (arguments.read("--points")) processTriangles = false; while (arguments.read("--triangles")) processTriangles = true; + osgDB::Registry::instance()->setBuildKdTreesHint(osgDB::ReaderWriter::Options::BUILD_KDTREES); + osg::ref_ptr scene = osgDB::readNodeFiles(arguments); if (!scene) @@ -88,7 +93,7 @@ int main(int argc, char **argv) osg::notify(osg::NOTICE)<<"Time to build "< +#include + +namespace osg +{ + +/** Implementation of a kdtree for Geometry leaves, to enable fast intersection tests.*/ +class OSG_EXPORT KdTree : public osg::Shape +{ + public: + + + KdTree() {} + + KdTree(const KdTree& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): + Shape(rhs,copyop) {} + + META_Shape(osg, KdTree) + + /** Build the kdtree from the specified source geometry object. + * retun true on success. */ + virtual bool build(osg::Geometry* geometry); + + + struct LineSegmentIntersection + { + LineSegmentIntersection(): + ratio(-1.0), + primitiveIndex(0) {} + + bool operator < (const LineSegmentIntersection& rhs) const { return ratio < rhs.ratio; } + + typedef std::vector IndexList; + typedef std::vector RatioList; + + double ratio; + osg::Vec3d intersectionPoint; + osg::Vec3 intersectionNormal; + IndexList indexList; + RatioList ratioList; + unsigned int primitiveIndex; + }; + + + typedef std::multiset LineSegmentIntersections; + + /** compute the intersection of a line segment and the kdtree, return true if an intersection has been found.*/ + virtual bool intersect(const osg::Vec3& start, const osg::Vec3& end, LineSegmentIntersections& intersections); + + + + typedef int value_type; + typedef std::vector< value_type > Indices; + + struct KDNode + { + KDNode(): + first(0), + second(0) {} + + KDNode(value_type f, value_type s): + first(f), + second(s) {} + + value_type first; + value_type second; + + osg::BoundingBox bb; + }; + + + struct KDLeaf + { + KDLeaf(): + first(0), + second(0) {} + + KDLeaf(value_type f, value_type s): + first(f), + second(s) {} + + value_type first; + value_type second; + + osg::BoundingBox bb; + }; + + struct Triangle + { + Triangle(unsigned int p1, unsigned int p2, unsigned int p3): + _p1(p1), _p2(p2), _p3(p3) {} + + bool operator < (const Triangle& rhs) const + { + if (_p1rhs._p1) return false; + if (_p2rhs._p2) return false; + return _p3 _kdTreePrototype; + + unsigned int _maxNumLevels; + unsigned int _targetNumTrianglesPerLeaf; + + unsigned int _numVerticesProcessed; + + protected: + + virtual ~KdTreeBuilder() {} + +}; + +} + +#endif diff --git a/include/osgDB/ReaderWriter b/include/osgDB/ReaderWriter index 0f04cf935..46ac357d2 100644 --- a/include/osgDB/ReaderWriter +++ b/include/osgDB/ReaderWriter @@ -86,22 +86,33 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object CACHE_OBJECTS | CACHE_SHADERS }; + + /// range of options of whether to build kdtrees automatically on loading + enum BuildKdTreesHint + { + NO_PREFERENCE, + DO_NOT_BUILD_KDTREES, + BUILD_KDTREES + }; Options(): osg::Object(true), - _objectCacheHint(CACHE_ARCHIVES) {} + _objectCacheHint(CACHE_ARCHIVES), + _buildKdTreesHint(NO_PREFERENCE) {} Options(const std::string& str): osg::Object(true), _str(str), - _objectCacheHint(CACHE_ARCHIVES) {} + _objectCacheHint(CACHE_ARCHIVES), + _buildKdTreesHint(NO_PREFERENCE) {} Options(const Options& options,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): osg::Object(options,copyop), _str(options._str), _databasePaths(options._databasePaths), - _objectCacheHint(options._objectCacheHint) {} + _objectCacheHint(options._objectCacheHint), + _buildKdTreesHint(options._buildKdTreesHint) {} META_Object(osgDB,Options); @@ -128,6 +139,14 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object CacheHintOptions getObjectCacheHint() const { return _objectCacheHint; } + /** Set whether the KdTrees should be built for geometry in the loader model. */ + void setBuildKdTreesHint(BuildKdTreesHint hint) { _buildKdTreesHint = hint; } + + /** Get whether the KdTrees should be built for geometry in the loader model. */ + BuildKdTreesHint getBuildKdTreesHint() const { return _buildKdTreesHint; } + + + /** Sets a plugindata value PluginData with a string */ void setPluginData(const std::string& s, void* v) const { _pluginData[s] = v; } @@ -151,6 +170,7 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object std::string _str; FilePathList _databasePaths; CacheHintOptions _objectCacheHint; + BuildKdTreesHint _buildKdTreesHint; typedef std::map PluginDataMap; mutable PluginDataMap _pluginData; diff --git a/include/osgDB/Registry b/include/osgDB/Registry index a2b87fa72..92f454b7a 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -130,7 +131,6 @@ class OSGDB_EXPORT Registry : public osg::Referenced bool writeObject(const osg::Object& obj,Output& fw); - class ReadFileCallback : public virtual osg::Referenced { public: @@ -188,8 +188,13 @@ class OSGDB_EXPORT Registry : public osg::Referenced ReaderWriter::ReadResult readObject(const std::string& fileName,const ReaderWriter::Options* options) { - if (_readFileCallback.valid()) return _readFileCallback->readObject(fileName,options); - else return readObjectImplementation(fileName,options); + ReaderWriter::ReadResult result = _readFileCallback.valid() ? + _readFileCallback->readObject(fileName,options) : + readObjectImplementation(fileName,options); + + buildKdTreeIfRequired(result, options); + + return result; } ReaderWriter::ReadResult readObjectImplementation(const std::string& fileName,const ReaderWriter::Options* options); @@ -209,8 +214,13 @@ class OSGDB_EXPORT Registry : public osg::Referenced ReaderWriter::ReadResult readNode(const std::string& fileName,const ReaderWriter::Options* options) { - if (_readFileCallback.valid()) return _readFileCallback->readNode(fileName,options); - else return readNodeImplementation(fileName,options); + ReaderWriter::ReadResult result = _readFileCallback.valid() ? + _readFileCallback->readNode(fileName,options) : + readNodeImplementation(fileName,options); + + buildKdTreeIfRequired(result, options); + + return result; } ReaderWriter::ReadResult readNodeImplementation(const std::string& fileName,const ReaderWriter::Options* options); @@ -302,6 +312,26 @@ class OSGDB_EXPORT Registry : public osg::Referenced ReaderWriter::WriteResult writeShaderImplementation(const osg::Shader& obj, const std::string& fileName,const ReaderWriter::Options* options); + inline void buildKdTreeIfRequired(ReaderWriter::ReadResult& result, const ReaderWriter::Options* options) + { + bool doKdTreeBuilder = (options && options->getBuildKdTreesHint()!=ReaderWriter::Options::NO_PREFERENCE) ? + options->getBuildKdTreesHint() == ReaderWriter::Options::BUILD_KDTREES : + _buildKdTreesHint == ReaderWriter::Options::BUILD_KDTREES; + + if (doKdTreeBuilder && _kdTreeBuilder.valid() && result.validNode()) + { + result.getNode()->accept(*_kdTreeBuilder); + } + } + + + void setBuildKdTreesHint(ReaderWriter::Options::BuildKdTreesHint hint) { _buildKdTreesHint = hint; } + ReaderWriter::Options::BuildKdTreesHint getBuildKdTreesHint() const { return _buildKdTreesHint; } + + void setKdTreeBuilder(osg::KdTreeBuilder* builder) { _kdTreeBuilder = builder; } + osg::KdTreeBuilder* getKdTreeBuilder() { return _kdTreeBuilder.get(); } + + void setCreateNodeFromImage(bool flag) { _createNodeFromImage = flag; } bool getCreateNodeFromImage() const { return _createNodeFromImage; } @@ -437,7 +467,10 @@ class OSGDB_EXPORT Registry : public osg::Referenced /** get the attached library with specified name.*/ DynamicLibraryList::iterator getLibraryItr(const std::string& fileName); - bool _createNodeFromImage; + ReaderWriter::Options::BuildKdTreesHint _buildKdTreesHint; + osg::ref_ptr _kdTreeBuilder; + + bool _createNodeFromImage; osg::Object* readObject(DotOsgWrapperMap& dowMap,Input& fr); diff --git a/src/osg/CMakeLists.txt b/src/osg/CMakeLists.txt index 52db498c2..828af1c8c 100644 --- a/src/osg/CMakeLists.txt +++ b/src/osg/CMakeLists.txt @@ -72,6 +72,7 @@ SET(LIB_PUBLIC_HEADERS ${HEADER_PATH}/Image ${HEADER_PATH}/ImageStream ${HEADER_PATH}/io_utils + ${HEADER_PATH}/KdTree ${HEADER_PATH}/Light ${HEADER_PATH}/LightModel ${HEADER_PATH}/LightSource @@ -228,6 +229,7 @@ ADD_LIBRARY(${LIB_NAME} Hint.cpp Image.cpp ImageStream.cpp + KdTree.cpp LOD.cpp Light.cpp LightModel.cpp diff --git a/src/osg/KdTree.cpp b/src/osg/KdTree.cpp new file mode 100644 index 000000000..040e5bf55 --- /dev/null +++ b/src/osg/KdTree.cpp @@ -0,0 +1,67 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * 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 + * OpenSceneGraph Public License for more details. +*/ + +#include +#include + +using namespace osg; + + +//////////////////////////////////////////////////////////////////////////////// +// +// KdTree + +bool KdTree::build(osg::Geometry* geometry) +{ + osg::notify(osg::NOTICE)<<"KdTree::build("<asGeometry(); + if (geom) + { + osg::KdTree* previous = dynamic_cast(geom->getShape()); + if (previous) continue; + + osg::ref_ptr kdTree = dynamic_cast(_kdTreePrototype->cloneType()); + + if (kdTree->build(geom)) + { + geom->setShape(kdTree.get()); + } + } + } +} diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index 9f19cc131..79c3b121e 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -158,6 +158,17 @@ Registry::Registry() // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify(). // notify(INFO) << "Constructing osg::Registry"<setUseDisplayList(false); geometry->setUseVertexBufferObjects(true); + + + if (osgDB::Registry::instance()->getBuildKdTreesHint()==osgDB::ReaderWriter::Options::BUILD_KDTREES && + osgDB::Registry::instance()->getKdTreeBuilder()) + { + //osg::notify(osg::NOTICE)<<"osgTerrain::GeometryTechnique::build kd tree"<accept(*(osgDB::Registry::instance()->getKdTreeBuilder())); + //osg::notify(osg::NOTICE)<<"after"<