From ac78d01b2b3c93223222b1a4697c726aafed22bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Jul 2017 13:11:44 +0200 Subject: [PATCH] Terrain: use the main camera's viewpoint for intersection tests Fixes lag spikes caused by intersection tests loading/unloading terrain pages. --- apps/openmw/mwrender/renderingmanager.cpp | 1 + components/terrain/quadtreenode.cpp | 19 ++++++++++++---- components/terrain/quadtreeworld.cpp | 5 +++++ components/terrain/quadtreeworld.hpp | 2 ++ components/terrain/viewdata.cpp | 27 +++++++++++++++++++++++ components/terrain/viewdata.hpp | 13 +++++++++++ components/terrain/world.hpp | 4 ++++ 7 files changed, 67 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6ee9b8ae8..4d4a36f6c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -222,6 +222,7 @@ namespace MWRender mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile)); else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile)); + mTerrain->setDefaultViewer(mViewer->getCamera()); mCamera.reset(new Camera(mViewer->getCamera())); diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 438303c27..801cdef5c 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -99,8 +99,10 @@ void QuadTreeNode::traverse(osg::NodeVisitor &nv) if (!hasValidBounds()) return; - if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv.getEyePoint())) || !getNumChildren()) - getView(nv)->add(this, true); + ViewData* vd = getView(nv); + + if ((mLodCallback && mLodCallback->isSufficientDetail(this, vd->getEyePoint())) || !getNumChildren()) + vd->add(this, true); else osg::Group::traverse(nv); } @@ -130,11 +132,20 @@ ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv) if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { osgUtil::CullVisitor* cv = static_cast(&nv); - return mViewDataMap->getViewData(cv->getCurrentCamera(), true); + ViewData* vd = mViewDataMap->getViewData(cv->getCurrentCamera(), true); + vd->setEyePoint(nv.getEyePoint()); + return vd; } else // INTERSECTION_VISITOR { - return mViewDataMap->getViewData(&nv, (nv.referenceCount() > 0)); // if no referenceCount, the visitor was allocated on the stack + static osg::ref_ptr dummyObj = new osg::DummyObject; + ViewData* vd = mViewDataMap->getViewData(dummyObj.get(), true); + ViewData* defaultView = mViewDataMap->getDefaultView(); + if (defaultView->hasEyePoint()) + vd->setEyePoint(defaultView->getEyePoint()); + else + vd->setEyePoint(nv.getEyePoint()); + return vd; } } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f2a80d673..f31064805 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -456,5 +456,10 @@ void QuadTreeWorld::reportStats(unsigned int frameNumber, osg::Stats *stats) stats->setAttribute(frameNumber, "Composite", mCompositeMapRenderer->getCompileSetSize()); } +void QuadTreeWorld::setDefaultViewer(osg::Object *obj) +{ + mViewDataMap->setDefaultViewer(obj); +} + } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 8ec75917b..ef33f158e 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -33,6 +33,8 @@ namespace Terrain void reportStats(unsigned int frameNumber, osg::Stats* stats); + virtual void setDefaultViewer(osg::Object* obj); + private: void ensureQuadTreeBuilt(); diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index 7b3df56b9..5e16537f4 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -7,6 +7,7 @@ ViewData::ViewData() : mNumEntries(0) , mFrameLastUsed(0) , mChanged(false) + , mHasEyePoint(false) { } @@ -43,6 +44,22 @@ bool ViewData::hasChanged() const return mChanged; } +bool ViewData::hasEyePoint() const +{ + return mHasEyePoint; +} + +void ViewData::setEyePoint(const osg::Vec3f &eye) +{ + mEyePoint = eye; + mHasEyePoint = true; +} + +const osg::Vec3f& ViewData::getEyePoint() const +{ + return mEyePoint; +} + void ViewData::reset(unsigned int frame) { // clear any unused entries @@ -150,5 +167,15 @@ void ViewDataMap::clear() mViewVector.clear(); } +void ViewDataMap::setDefaultViewer(osg::Object *viewer) +{ + mDefaultViewer = viewer; +} + +ViewData* ViewDataMap::getDefaultView() +{ + return getViewData(mDefaultViewer, true); +} + } diff --git a/components/terrain/viewdata.hpp b/components/terrain/viewdata.hpp index 30563d566..e4bfbd10c 100644 --- a/components/terrain/viewdata.hpp +++ b/components/terrain/viewdata.hpp @@ -52,12 +52,19 @@ namespace Terrain /// @return Have any nodes changed since the last frame bool hasChanged() const; + bool hasEyePoint() const; + + void setEyePoint(const osg::Vec3f& eye); + const osg::Vec3f& getEyePoint() const; + private: std::vector mEntries; unsigned int mNumEntries; unsigned int mFrameLastUsed; bool mChanged; osg::ref_ptr mViewer; + osg::Vec3f mEyePoint; + bool mHasEyePoint; }; class ViewDataMap : public osg::Referenced @@ -71,6 +78,10 @@ namespace Terrain void clear(); + void setDefaultViewer(osg::Object* viewer); + + ViewData* getDefaultView(); + private: std::list mViewVector; @@ -78,6 +89,8 @@ namespace Terrain Map mViews; std::deque mUnusedViews; + + osg::ref_ptr mDefaultViewer; }; } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 1eafc8bd7..d0576fbd3 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -14,6 +14,7 @@ namespace osg class Group; class Stats; class Node; + class Object; } namespace Resource @@ -87,6 +88,9 @@ namespace Terrain virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) {} + /// Set the default viewer (usually a Camera), used as viewpoint for any viewers that don't use their own viewpoint. + virtual void setDefaultViewer(osg::Object* obj) {} + Storage* getStorage() { return mStorage; } protected: