Reuse traversal result for different traversal with same view point

Rename eyePoint to viewPoint to match OSG conventions (eyePoint is the camera position, viewPoint is for LOD handling)
pull/2277/head
bzzt 6 years ago committed by Andrei Kortunov
parent 5508153d52
commit 63ab7345be

@ -382,7 +382,7 @@ namespace MWWorld
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
{
mWorld->preload(mTerrainViews[i], mPreloadPositions[i], mAbort);
mTerrainViews[i]->reset(0);
mTerrainViews[i]->reset();
}
}

@ -114,9 +114,10 @@ void QuadTreeNode::traverse(osg::NodeVisitor &nv)
if (!hasValidBounds())
return;
ViewData* vd = getView(nv);
bool needsUpdate = true;
ViewData* vd = getView(nv, needsUpdate);
if ((mLodCallback && mLodCallback->isSufficientDetail(this, distance(vd->getEyePoint()))) || !getNumChildren())
if ((mLodCallback && mLodCallback->isSufficientDetail(this, distance(vd->getViewPoint()))) || !getNumChildren())
vd->add(this, true);
else
osg::Group::traverse(nv);
@ -142,26 +143,24 @@ ViewDataMap *QuadTreeNode::getViewDataMap()
return mViewDataMap;
}
ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv)
ViewData* QuadTreeNode::getView(osg::NodeVisitor &nv, bool& needsUpdate)
{
ViewData* vd = NULL;
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
ViewData* vd = mViewDataMap->getViewData(cv->getCurrentCamera());
vd->setEyePoint(nv.getViewPoint());
return vd;
vd = mViewDataMap->getViewData(cv->getCurrentCamera(), nv.getViewPoint(), needsUpdate);
}
else // INTERSECTION_VISITOR
{
osg::Vec3f viewPoint = nv.getViewPoint();
mViewDataMap->getDefaultViewPoint(viewPoint);
static osg::ref_ptr<osg::Object> dummyObj = new osg::DummyObject;
ViewData* vd = mViewDataMap->getViewData(dummyObj.get());
ViewData* defaultView = mViewDataMap->getDefaultView();
if (defaultView->hasEyePoint())
vd->setEyePoint(defaultView->getEyePoint());
else
vd->setEyePoint(nv.getEyePoint());
return vd;
vd = mViewDataMap->getViewData(dummyObj.get(), viewPoint, needsUpdate);
needsUpdate = true;
}
return vd;
}
void QuadTreeNode::setBoundingBox(const osg::BoundingBox &boundingBox)

@ -85,7 +85,7 @@ namespace Terrain
ViewDataMap* getViewDataMap();
/// Create or retrieve a view for the given traversal.
ViewData* getView(osg::NodeVisitor& nv);
ViewData* getView(osg::NodeVisitor& nv, bool& needsUpdate);
private:
QuadTreeNode* mParent;

@ -247,7 +247,7 @@ QuadTreeWorld::~QuadTreeWorld()
}
void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& eyePoint, bool visible, float maxDist)
void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallback* lodCallback, const osg::Vec3f& viewPoint, bool visible, float maxDist)
{
if (!node->hasValidBounds())
return;
@ -255,7 +255,7 @@ void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallbac
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
visible = visible && !static_cast<osgUtil::CullVisitor*>(nv)->isCulled(node->getBoundingBox());
float dist = node->distance(eyePoint);
float dist = node->distance(viewPoint);
if (dist > maxDist)
return;
@ -266,7 +266,7 @@ void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, LodCallbac
else
{
for (unsigned int i=0; i<node->getNumChildren(); ++i)
traverse(node->getChild(i), vd, nv, lodCallback, eyePoint, visible, maxDist);
traverse(node->getChild(i), vd, nv, lodCallback, viewPoint, visible, maxDist);
}
}
@ -367,7 +367,8 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, C
void QuadTreeWorld::accept(osg::NodeVisitor &nv)
{
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR)
bool isCullVisitor = nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR;
if (!isCullVisitor && nv.getVisitorType() != osg::NodeVisitor::INTERSECTION_VISITOR)
{
if (nv.getName().find("AcceptedByComponentsTerrainQuadTreeWorld") != std::string::npos)
{
@ -382,26 +383,40 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
return;
}
ViewData* vd = mRootNode->getView(nv);
bool needsUpdate = false;
ViewData* vd = mRootNode->getView(nv, needsUpdate);
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
if (needsUpdate)
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
osg::UserDataContainer* udc = cv->getCurrentCamera()->getUserDataContainer();
if (udc && udc->getNumDescriptions() >= 2 && udc->getDescriptions()[0] == "NoTerrainLod")
vd->reset();
if (isCullVisitor)
{
std::istringstream stream(udc->getDescriptions()[1]);
int x,y;
stream >> x;
stream >> y;
traverseToCell(mRootNode.get(), vd, x,y);
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
osg::UserDataContainer* udc = cv->getCurrentCamera()->getUserDataContainer();
if (udc && udc->getNumDescriptions() >= 2 && udc->getDescriptions()[0] == "NoTerrainLod")
{
std::istringstream stream(udc->getDescriptions()[1]);
int x,y;
stream >> x;
stream >> y;
traverseToCell(mRootNode.get(), vd, x,y);
}
else
traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true, mViewDistance);
}
else
traverse(mRootNode.get(), vd, cv, mRootNode->getLodCallback(), cv->getViewPoint(), true, mViewDistance);
mRootNode->traverse(nv);
}
else if (isCullVisitor)
{
// view point is the same, but must still update visible status in case the camera has rotated
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
{
ViewData::Entry& entry = vd->getEntry(i);
entry.set(entry.mNode, !static_cast<osgUtil::CullVisitor*>(&nv)->isCulled(entry.mNode->getBoundingBox()));
}
}
else
mRootNode->traverse(nv);
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
{
@ -416,13 +431,16 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
{
mCompositeMapRenderer->setImmediate(static_cast<CompositeMap*>(udc->getUserData()));
udc->setUserData(nullptr);
}
entry.mRenderingNode->accept(nv);
}
}
vd->reset(nv.getTraversalNumber());
if (!isCullVisitor)
vd->reset(); // we can't reuse intersection views in the next frame because they only contain what is touched by the intersection ray.
vd->finishFrame(nv.getTraversalNumber());
mRootNode->getViewDataMap()->clearUnusedViews(nv.getTraversalNumber());
}
@ -473,12 +491,13 @@ View* QuadTreeWorld::createView()
return new ViewData;
}
void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint, std::atomic<bool> &abort)
void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, std::atomic<bool> &abort)
{
ensureQuadTreeBuilt();
ViewData* vd = static_cast<ViewData*>(view);
traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), eyePoint, false, mViewDistance);
vd->setViewPoint(viewPoint);
traverse(mRootNode.get(), vd, nullptr, mRootNode->getLodCallback(), viewPoint, false, mViewDistance);
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
{

@ -37,7 +37,8 @@ namespace Terrain
virtual void unloadCell(int x, int y);
View* createView();
void preload(View* view, const osg::Vec3f& eyePoint, std::atomic<bool>& abort);
void preload(View* view, const osg::Vec3f& viewPoint, std::atomic<bool>& abort);
void reportStats(unsigned int frameNumber, osg::Stats* stats);

@ -15,7 +15,7 @@ class MyView : public View
public:
osg::ref_ptr<osg::Node> mLoaded;
virtual void reset(unsigned int frame) {}
virtual void reset() {}
};
TerrainGrid::TerrainGrid(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask)

@ -7,7 +7,7 @@ ViewData::ViewData()
: mNumEntries(0)
, mFrameLastUsed(0)
, mChanged(false)
, mHasEyePoint(false)
, mHasViewPoint(false)
{
}
@ -17,6 +17,15 @@ ViewData::~ViewData()
}
void ViewData::copyFrom(const ViewData& other)
{
mNumEntries = other.mNumEntries;
mEntries = other.mEntries;
mChanged = other.mChanged;
mHasViewPoint = other.mHasViewPoint;
mViewPoint = other.mViewPoint;
}
void ViewData::add(QuadTreeNode *node, bool visible)
{
unsigned int index = mNumEntries++;
@ -44,23 +53,23 @@ bool ViewData::hasChanged() const
return mChanged;
}
bool ViewData::hasEyePoint() const
bool ViewData::hasViewPoint() const
{
return mHasEyePoint;
return mHasViewPoint;
}
void ViewData::setEyePoint(const osg::Vec3f &eye)
void ViewData::setViewPoint(const osg::Vec3f &viewPoint)
{
mEyePoint = eye;
mHasEyePoint = true;
mViewPoint = viewPoint;
mHasViewPoint = true;
}
const osg::Vec3f& ViewData::getEyePoint() const
const osg::Vec3f& ViewData::getViewPoint() const
{
return mEyePoint;
return mViewPoint;
}
void ViewData::reset(unsigned int frame)
void ViewData::reset()
{
// clear any unused entries
for (unsigned int i=mNumEntries; i<mEntries.size(); ++i)
@ -69,8 +78,6 @@ void ViewData::reset(unsigned int frame)
// reset index for next frame
mNumEntries = 0;
mChanged = false;
mFrameLastUsed = frame;
}
void ViewData::clear()
@ -80,6 +87,7 @@ void ViewData::clear()
mNumEntries = 0;
mFrameLastUsed = 0;
mChanged = false;
mHasViewPoint = false;
}
bool ViewData::contains(QuadTreeNode *node)
@ -112,17 +120,42 @@ bool ViewData::Entry::set(QuadTreeNode *node, bool visible)
}
}
ViewData *ViewDataMap::getViewData(osg::Object *viewer)
bool suitable(ViewData* vd, const osg::Vec3f& viewPoint, float& maxDist)
{
return vd->hasViewPoint() && (vd->getViewPoint() - viewPoint).length2() < maxDist*maxDist;
}
ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPoint, bool& needsUpdate)
{
Map::const_iterator found = mViews.find(viewer);
ViewData* vd = nullptr;
if (found == mViews.end())
{
ViewData* vd = createOrReuseView();
vd = createOrReuseView();
vd->setViewer(viewer);
mViews[viewer] = vd;
return vd;
}
else
return found->second;
vd = found->second;
if (!suitable(vd, viewPoint, mReuseDistance))
{
for (Map::const_iterator other = mViews.begin(); other != mViews.end(); ++other)
{
if (suitable(other->second, viewPoint, mReuseDistance) && other->second->getNumEntries())
{
vd->copyFrom(*other->second);
needsUpdate = false;
return vd;
}
}
vd->setViewPoint(viewPoint);
needsUpdate = true;
}
else
needsUpdate = false;
return vd;
}
ViewData *ViewDataMap::createOrReuseView()
@ -168,9 +201,16 @@ void ViewDataMap::setDefaultViewer(osg::Object *viewer)
mDefaultViewer = viewer;
}
ViewData* ViewDataMap::getDefaultView()
bool ViewDataMap::getDefaultViewPoint(osg::Vec3f& viewPoint)
{
return getViewData(mDefaultViewer);
Map::const_iterator found = mViews.find(mDefaultViewer);
if (found != mViews.end() && found->second->hasViewPoint())
{
viewPoint = found->second->getViewPoint();
return true;
}
else
return false;
}

@ -21,12 +21,14 @@ namespace Terrain
void add(QuadTreeNode* node, bool visible);
void reset(unsigned int frame);
void reset();
void clear();
bool contains(QuadTreeNode* node);
void copyFrom(const ViewData& other);
struct Entry
{
Entry();
@ -45,28 +47,34 @@ namespace Terrain
Entry& getEntry(unsigned int i);
unsigned int getFrameLastUsed() const { return mFrameLastUsed; }
void finishFrame(unsigned int frame) { mFrameLastUsed = frame; mChanged = false; }
/// @return Have any nodes changed since the last frame
bool hasChanged() const;
bool hasEyePoint() const;
bool hasViewPoint() const;
void setEyePoint(const osg::Vec3f& eye);
const osg::Vec3f& getEyePoint() const;
void setViewPoint(const osg::Vec3f& viewPoint);
const osg::Vec3f& getViewPoint() const;
private:
std::vector<Entry> mEntries;
unsigned int mNumEntries;
unsigned int mFrameLastUsed;
bool mChanged;
osg::Vec3f mEyePoint;
bool mHasEyePoint;
osg::Vec3f mViewPoint;
bool mHasViewPoint;
float mReuseDistance;
};
class ViewDataMap : public osg::Referenced
{
public:
ViewData* getViewData(osg::Object* viewer);
ViewDataMap()
: mReuseDistance(100) // large value should be safe because the visibility of each node is still updated individually for each camera even if the base view was reused.
{}
ViewData* getViewData(osg::Object* viewer, const osg::Vec3f& viewPoint, bool& needsUpdate);
ViewData* createOrReuseView();
@ -76,7 +84,7 @@ namespace Terrain
void setDefaultViewer(osg::Object* viewer);
ViewData* getDefaultView();
bool getDefaultViewPoint(osg::Vec3f& viewPoint);
private:
std::list<ViewData> mViewVector;
@ -84,6 +92,8 @@ namespace Terrain
typedef std::map<osg::ref_ptr<osg::Object>, ViewData*> Map;
Map mViews;
float mReuseDistance;
std::deque<ViewData*> mUnusedViews;
osg::ref_ptr<osg::Object> mDefaultViewer;

@ -8,6 +8,7 @@
#include <atomic>
#include <memory>
#include <set>
#include <atomic>
#include "defs.hpp"
#include "cellborder.hpp"
@ -48,7 +49,7 @@ namespace Terrain
virtual ~View() {}
/// Reset internal structure so that the next addition to the view will override the previous frame's contents.
virtual void reset(unsigned int frame) = 0;
virtual void reset() = 0;
};
/**
@ -102,7 +103,8 @@ namespace Terrain
virtual View* createView() { return nullptr; }
/// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads.
virtual void preload(View* view, const osg::Vec3f& eyePoint, std::atomic<bool>& abort) {}
virtual void preload(View* view, const osg::Vec3f& viewPoint, std::atomic<bool>& abort) {}
virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) {}

Loading…
Cancel
Save