/* -*-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 #include #include #include #include using namespace osg; //#define VERBOSE_OUTPUT //////////////////////////////////////////////////////////////////////////////// // // BuildKdTree Declarartion - class used for building an single KdTree struct BuildKdTree { BuildKdTree(KdTree& kdTree): _kdTree(kdTree) {} typedef std::vector< osg::Vec3 > CenterList; typedef std::vector< unsigned int > Indices; typedef std::vector< unsigned int > AxisStack; bool build(KdTree::BuildOptions& options, osg::Geometry* geometry); void computeDivisions(KdTree::BuildOptions& options); int divide(KdTree::BuildOptions& options, osg::BoundingBox& bb, int nodeIndex, unsigned int level); KdTree& _kdTree; osg::BoundingBox _bb; AxisStack _axisStack; Indices _primitiveIndices; CenterList _centers; protected: BuildKdTree& operator = (const BuildKdTree&) { return *this; } }; struct PrimitiveIndicesCollector { PrimitiveIndicesCollector(): _buildKdTree(0) { } inline void operator () (unsigned int p0) { //OSG_NOTICE<<" point ("<_kdTree.getVertices()))[p0]; _buildKdTree->_kdTree.addPoint(p0); osg::BoundingBox bb; bb.expandBy(v0); _buildKdTree->_primitiveIndices.push_back(_buildKdTree->_centers.size()); _buildKdTree->_centers.push_back(bb.center()); } inline void operator () (unsigned int p0, unsigned int p1) { //OSG_NOTICE<<" line ("<_kdTree.getVertices()))[p0]; const osg::Vec3& v1 = (*(_buildKdTree->_kdTree.getVertices()))[p1]; // discard degenerate points if (v0==v1) { //OSG_NOTICE<<"Disgarding degenerate triangle"<_kdTree._degenerateCount++; return; } _buildKdTree->_kdTree.addLine(p0,p1); osg::BoundingBox bb; bb.expandBy(v0); bb.expandBy(v1); _buildKdTree->_primitiveIndices.push_back(_buildKdTree->_centers.size()); _buildKdTree->_centers.push_back(bb.center()); } inline void operator () (unsigned int p0, unsigned int p1, unsigned int p2) { // OSG_NOTICE<<" triangle ("<_kdTree.getVertices()))[p0]; const osg::Vec3& v1 = (*(_buildKdTree->_kdTree.getVertices()))[p1]; const osg::Vec3& v2 = (*(_buildKdTree->_kdTree.getVertices()))[p2]; // discard degenerate points if (v0==v1 || v1==v2 || v2==v0) { //OSG_NOTICE<<"Disgarding degenerate triangle"<_kdTree._degenerateCount++; return; } _buildKdTree->_kdTree.addTriangle(p0,p1,p2); osg::BoundingBox bb; bb.expandBy(v0); bb.expandBy(v1); bb.expandBy(v2); _buildKdTree->_primitiveIndices.push_back(_buildKdTree->_centers.size()); _buildKdTree->_centers.push_back(bb.center()); } inline void operator () (unsigned int p0, unsigned int p1, unsigned int p2, unsigned int p3) { //OSG_NOTICE<<" quad ("<_kdTree.getVertices()))[p0]; const osg::Vec3& v1 = (*(_buildKdTree->_kdTree.getVertices()))[p1]; const osg::Vec3& v2 = (*(_buildKdTree->_kdTree.getVertices()))[p2]; const osg::Vec3& v3 = (*(_buildKdTree->_kdTree.getVertices()))[p3]; // discard degenerate points if (v0==v1 || v1==v2 || v2==v0 || v3==v0 || v3==v1 || v3==v2) { //OSG_NOTICE<<"Disgarding degenerate quad"<_kdTree._degenerateCount++; return; } _buildKdTree->_kdTree.addQuad(p0,p1,p2,p3); osg::BoundingBox bb; bb.expandBy(v0); bb.expandBy(v1); bb.expandBy(v2); bb.expandBy(v3); _buildKdTree->_primitiveIndices.push_back(_buildKdTree->_centers.size()); _buildKdTree->_centers.push_back(bb.center()); } BuildKdTree* _buildKdTree; }; //////////////////////////////////////////////////////////////////////////////// // // BuildKdTree Implementation bool BuildKdTree::build(KdTree::BuildOptions& options, osg::Geometry* geometry) { #ifdef VERBOSE_OUTPUT OSG_NOTICE<<"osg::KDTreeBuilder::createKDTree()"<(geometry->getVertexArray()); if (!vertices) return false; if (vertices->size() <= options._targetNumTrianglesPerLeaf) return false; _bb = geometry->getBoundingBox(); _kdTree.setVertices(vertices); unsigned int estimatedSize = (unsigned int)(2.0*float(vertices->size())/float(options._targetNumTrianglesPerLeaf)); #ifdef VERBOSE_OUTPUT OSG_NOTICE<<"kdTree->_kdNodes.reserve()="<size(); unsigned int estimatedNumTriangles = vertices->size()*2; _primitiveIndices.reserve(estimatedNumTriangles); _centers.reserve(estimatedNumTriangles); osg::TemplatePrimitiveIndexFunctor collectIndices; collectIndices._buildKdTree = this; geometry->accept(collectIndices); _primitiveIndices.reserve(vertices->size()); KdTree::KdNode node(-1, _primitiveIndices.size()); node.bb = _bb; int nodeNum = _kdTree.addNode(node); osg::BoundingBox bb = _bb; nodeNum = divide(options, bb, nodeNum, 0); osg::KdTree::Indices& primitiveIndices = _kdTree.getPrimitiveIndices(); KdTree::Indices new_indices; new_indices.reserve(_primitiveIndices.size()); for(Indices::iterator itr = _primitiveIndices.begin(); itr != _primitiveIndices.end(); ++itr) { new_indices.push_back(primitiveIndices[*itr]); } primitiveIndices.swap(new_indices); #ifdef VERBOSE_OUTPUT OSG_NOTICE<<"Root nodeNum="<=dimensions[1]) { if (dimensions[0]>=dimensions[2]) axis = 0; else axis = 2; } else if (dimensions[1]>=dimensions[2]) axis = 1; else axis = 2; _axisStack.push_back(axis); dimensions[axis] /= 2.0f; #ifdef VERBOSE_OUTPUT OSG_NOTICE<<" "<(node.second)>options._targetNumTrianglesPerLeaf); if (!needToDivide) { if (node.first<0) { int istart = -node.first-1; int iend = istart+node.second-1; // leaf is done, now compute bound on it. node.bb.init(); for(int i=istart; i<=iend; ++i) { unsigned int primitiveIndex = _kdTree.getPrimitiveIndices()[_primitiveIndices[i]]; primitiveIndex++; //skip original Primitive index unsigned int numPoints = _kdTree.getVertexIndices()[primitiveIndex++]; for(; numPoints>0; --numPoints) { unsigned int vi = _kdTree.getVertexIndices()[primitiveIndex++]; const osg::Vec3& v = (*_kdTree.getVertices())[vi]; node.bb.expandBy(v); } } if (node.bb.valid()) { float epsilon = 1e-6f; node.bb._min.x() -= epsilon; node.bb._min.y() -= epsilon; node.bb._min.z() -= epsilon; node.bb._max.x() += epsilon; node.bb._max.y() += epsilon; node.bb._max.z() += epsilon; } #ifdef VERBOSE_OUTPUT if (!node.bb.valid()) { OSG_NOTICE<<"After reset "<mid)) { --right; } if (left resize could // have invalidate the previous node ref. KdTree::KdNode& newNodeRef = _kdTree.getNode(nodeIndex); newNodeRef.first = leftChildIndex; newNodeRef.second = rightChildIndex; insitueDivision = true; newNodeRef.bb.init(); if (leftChildIndex!=0) newNodeRef.bb.expandBy(_kdTree.getNode(leftChildIndex).bb); if (rightChildIndex!=0) newNodeRef.bb.expandBy(_kdTree.getNode(rightChildIndex).bb); if (!newNodeRef.bb.valid()) { OSG_NOTICE<<"leftChildIndex="<(geometry.getShape()); if (previous) return; osg::ref_ptr kdTree = osg::clone(_kdTreePrototype.get()); if (kdTree->build(_buildOptions, &geometry)) { geometry.setShape(kdTree.get()); } }