/* -*-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 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; } }; //////////////////////////////////////////////////////////////////////////////// // // Functor for collecting triangle indices from Geometry struct TriangleIndicesCollector { TriangleIndicesCollector(): _buildKdTree(0) { } inline void operator () (unsigned int p0, unsigned int p1, unsigned int p2) { const osg::Vec3& v0 = (*(_buildKdTree->_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 || v1==v2) { //osg::notify(osg::NOTICE)<<"Disgarding degenerate triangle"<_kdTree.addTriangle(KdTree::Triangle(p0,p1,p2)); osg::BoundingBox bb; bb.expandBy(v0); bb.expandBy(v1); bb.expandBy(v2); _buildKdTree->_centers.push_back(bb.center()); _buildKdTree->_primitiveIndices.push_back(i); } BuildKdTree* _buildKdTree; }; //////////////////////////////////////////////////////////////////////////////// // // BuildKdTree Implementation bool BuildKdTree::build(KdTree::BuildOptions& options, osg::Geometry* geometry) { #ifdef VERBOSE_OUTPUT osg::notify(osg::NOTICE)<<"osg::KDTreeBuilder::createKDTree()"<(geometry->getVertexArray()); if (!vertices) return false; if (vertices->size() <= options._targetNumTrianglesPerLeaf) return false; _bb = geometry->getBound(); _kdTree.setVertices(vertices); unsigned int estimatedSize = (unsigned int)(2.0*float(vertices->size())/float(options._targetNumTrianglesPerLeaf)); #ifdef VERBOSE_OUTPUT osg::notify(osg::NOTICE)<<"kdTree->_kdNodes.reserve()="<size(); unsigned int estimatedNumTriangles = vertices->size()*2; _primitiveIndices.reserve(estimatedNumTriangles); _centers.reserve(estimatedNumTriangles); _kdTree.getTriangles().reserve(estimatedNumTriangles); osg::TriangleIndexFunctor collectTriangleIndices; collectTriangleIndices._buildKdTree = this; geometry->accept(collectTriangleIndices); _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); // now reorder the triangle list so that it's in order as per the primitiveIndex list. KdTree::TriangleList triangleList(_kdTree.getTriangles().size()); for(unsigned int i=0; i<_primitiveIndices.size(); ++i) { triangleList[i] = _kdTree.getTriangle(_primitiveIndices[i]); } _kdTree.getTriangles().swap(triangleList); #ifdef VERBOSE_OUTPUT osg::notify(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::notify(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) { const KdTree::Triangle& tri = _kdTree.getTriangle(_primitiveIndices[i]); const osg::Vec3& v0 = (*_kdTree.getVertices())[tri.p0]; const osg::Vec3& v1 = (*_kdTree.getVertices())[tri.p1]; const osg::Vec3& v2 = (*_kdTree.getVertices())[tri.p2]; node.bb.expandBy(v0); node.bb.expandBy(v1); node.bb.expandBy(v2); } 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::notify(osg::NOTICE)<<"After reset "<mid)) { --right; } while(leftmid)) { --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::notify(osg::NOTICE)<<"leftChildIndex="<esplison) { float u = (P*T); if (u<0.0 || u>det) continue; osg::Vec3 Q = T ^ E1; float v = (Q*_d); if (v<0.0 || v>det) continue; if ((u+v)> det) continue; float inv_det = 1.0f/det; float t = (Q*E2)*inv_det; if (t<0.0 || t>_length) continue; u *= inv_det; v *= inv_det; r0 = 1.0f-u-v; r1 = u; r2 = v; r = t * _inverse_length; } else if (det<-esplison) { float u = (P*T); if (u>0.0 || u0.0 || v_length) continue; u *= inv_det; v *= inv_det; r0 = 1.0f-u-v; r1 = u; r2 = v; r = t * _inverse_length; } else { continue; } osg::Vec3 in = v0*r0 + v1*r1 + v2*r2; osg::Vec3 normal = E1^E2; normal.normalize(); #if 1 _intersections.push_back(KdTree::LineSegmentIntersection()); KdTree::LineSegmentIntersection& intersection = _intersections.back(); intersection.ratio = r; intersection.primitiveIndex = i; intersection.intersectionPoint = in; intersection.intersectionNormal = normal; intersection.p0 = tri.p0; intersection.p1 = tri.p1; intersection.p2 = tri.p2; intersection.r0 = r0; intersection.r1 = r1; intersection.r2 = r2; #endif // osg::notify(osg::NOTICE)<<" got intersection ("<asGeometry(); if (geom) { osg::KdTree* previous = dynamic_cast(geom->getShape()); if (previous) continue; osg::ref_ptr kdTree = dynamic_cast(_kdTreePrototype->cloneType()); if (kdTree->build(_buildOptions, geom)) { geom->setShape(kdTree.get()); } } } }