mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:53:51 +00:00
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)
This commit is contained in:
parent
5508153d52
commit
63ab7345be
9 changed files with 136 additions and 65 deletions
|
@ -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…
Reference in a new issue