diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 6072ee904d..b842c172dc 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -154,18 +154,21 @@ void QuadTreeNode::traverseTo(ViewData* vd, float size, const osg::Vec2f& center } } -void QuadTreeNode::traverse(osg::NodeVisitor &nv) +void QuadTreeNode::intersect(ViewData* vd, TerrainLineIntersector* intersector) { if (!hasValidBounds()) return; - bool needsUpdate = true; - ViewData* vd = getView(nv, needsUpdate); + if (!intersector->intersectAndClip(getBoundingBox())) + return; - if ((mLodCallback && mLodCallback->isSufficientDetail(this, distance(vd->getViewPoint()))) || !getNumChildren()) + if (getNumChildren() == 0) vd->add(this, true); else - osg::Group::traverse(nv); + { + for (unsigned int i=0; iintersect(vd, intersector); + } } void QuadTreeNode::setLodCallback(LodCallback *lodCallback) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index aca05cfed0..e52d2db938 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -2,12 +2,31 @@ #define OPENMW_COMPONENTS_TERRAIN_QUADTREENODE_H #include +#include #include "defs.hpp" namespace Terrain { + class TerrainLineIntersector : public osgUtil::LineSegmentIntersector + { + public: + TerrainLineIntersector(osgUtil::LineSegmentIntersector* intersector, osg::Matrix& matrix) : + osgUtil::LineSegmentIntersector(intersector->getStart() * matrix, intersector->getEnd() * matrix) + { + setPrecisionHint(intersector->getPrecisionHint()); + _intersectionLimit = intersector->getIntersectionLimit(); + _parent = intersector; + } + + bool intersectAndClip(const osg::BoundingBox& bbInput) + { + osg::Vec3d s(_start), e(_end); + return osgUtil::LineSegmentIntersector::intersectAndClip(s, e, bbInput); + } + }; + enum ChildDirection { NW = 0, @@ -72,9 +91,6 @@ namespace Terrain /// center in cell coordinates const osg::Vec2f& getCenter() const; - /// Traverse the child tree and populate the ViewData - virtual void traverse(osg::NodeVisitor& nv); - /// Optimized version of traverse() that doesn't incur the overhead of NodeVisitor double-dispatch or fetching the various variables. /// Note this doesn't do any culling for non-cull visitors (e.g. intersections) so it shouldn't be used for those. void traverse(ViewData* vd, osg::NodeVisitor* nv, const osg::Vec3f& viewPoint, bool visible, float maxDist); @@ -82,6 +98,9 @@ namespace Terrain /// Traverse to a specific node and add only that node. void traverseTo(ViewData* vd, float size, const osg::Vec2f& center); + /// Adds all leaf nodes which intersect the line from start to end + void intersect(ViewData* vd, TerrainLineIntersector* intersector); + /// Set the Lod callback to use for determining when to stop traversing further down the quad tree. void setLodCallback(LodCallback* lodCallback); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 430fcd025c..899e9c7f14 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -360,7 +360,18 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) mRootNode->traverse(vd, &nv, cv->getViewPoint(), true, mViewDistance); } else - mRootNode->traverse(nv); + { + osgUtil::IntersectionVisitor* iv = static_cast(&nv); + osgUtil::LineSegmentIntersector* lineIntsersector = dynamic_cast(iv->getIntersector()); + if (!lineIntsersector) + throw std::runtime_error("Can not update QuadTreeWorld - the LineSegmentIntersector expected"); + + osg::Matrix matrix = osg::Matrix::identity(); + if (lineIntsersector->getCoordinateFrame() == osgUtil::Intersector::CoordinateFrame::MODEL && iv->getModelMatrix() == 0) + matrix = lineIntsersector->getTransformation(*iv, osgUtil::Intersector::CoordinateFrame::MODEL); + osg::ref_ptr terrainIntersector (new TerrainLineIntersector(lineIntsersector, matrix)); + mRootNode->intersect(vd, terrainIntersector); + } } else if (isCullVisitor) {