From c7fda6d28004fa9be927c0f48d4cede21773d991 Mon Sep 17 00:00:00 2001 From: bzzt lost a hitlab login Date: Sun, 10 May 2020 13:37:00 +0000 Subject: [PATCH] activegrid paging = 2xfps Signed-off-by: Bret Curtis --- apps/openmw/mwrender/objectpaging.cpp | 86 +++++++++++++++++++---- apps/openmw/mwrender/objectpaging.hpp | 9 ++- apps/openmw/mwrender/renderingmanager.cpp | 5 ++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwworld/cellpreloader.cpp | 4 +- apps/openmw/mwworld/cellpreloader.hpp | 2 +- apps/openmw/mwworld/scene.cpp | 48 ++++++++----- apps/openmw/mwworld/scene.hpp | 2 + components/terrain/quadtreenode.cpp | 18 ++--- components/terrain/quadtreenode.hpp | 10 ++- components/terrain/quadtreeworld.cpp | 35 +++++---- components/terrain/quadtreeworld.hpp | 1 - files/settings-default.cfg | 5 +- 13 files changed, 158 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index eb71f0993c..9b3165d87a 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -32,16 +33,19 @@ namespace MWRender { - bool typeFilter(int type, bool far) + bool typeFilter(int type, bool far, bool activeGrid) { switch (type) { case ESM::REC_STAT: - case ESM::REC_ACTI: - case ESM::REC_DOOR: - return true; + return true; + + case ESM::REC_ACTI: // TODO enable when intersectionvisitor supported + case ESM::REC_DOOR: + return !activeGrid; case ESM::REC_CONT: - return far ? false : true; + return far ? false : !activeGrid; + default: return false; } @@ -64,17 +68,19 @@ namespace MWRender } } - osg::ref_ptr ObjectPaging::getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool far, const osg::Vec3f& viewPoint, bool compile) + osg::ref_ptr ObjectPaging::getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) { - if (!far)return nullptr; - ChunkId id = std::make_tuple(center, size); + if (activeGrid && !mActiveGrid) + return nullptr; + + ChunkId id = std::make_tuple(center, size, activeGrid); osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) return obj->asNode(); else { - osg::ref_ptr node = createChunk(size, center, viewPoint, compile); + osg::ref_ptr node = createChunk(size, center, activeGrid, viewPoint, compile); mCache->addEntryToObjectCache(id, node.get()); return node; } @@ -231,6 +237,15 @@ namespace MWRender std::vector> mObjects; }; + class RefnumSet : public osg::Object + { + public: + RefnumSet(){} + RefnumSet(const RefnumSet& copy, const osg::CopyOp&) : mRefnums(copy.mRefnums) {} + META_Object(MWRender, RefnumSet) + std::set mRefnums; + }; + class AnalyzeVisitor : public osg::NodeVisitor { public: @@ -310,6 +325,7 @@ namespace MWRender : GenericResourceManager(nullptr) , mSceneManager(sceneManager) { + mActiveGrid = Settings::Manager::getBool("object paging active grid", "Terrain"); mDebugBatches = Settings::Manager::getBool("object paging debug batches", "Terrain"); mMergeFactor = Settings::Manager::getFloat("object paging merge factor", "Terrain"); mMinSize = Settings::Manager::getFloat("object paging min size", "Terrain"); @@ -317,7 +333,7 @@ namespace MWRender mMinSizeCostMultiplier = Settings::Manager::getFloat("object paging min size cost multiplier", "Terrain"); } - osg::ref_ptr ObjectPaging::createChunk(float size, const osg::Vec2f& center, const osg::Vec3f& viewPoint, bool compile) + osg::ref_ptr ObjectPaging::createChunk(float size, const osg::Vec2f& center, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) { osg::Vec2i startCell = osg::Vec2i(std::floor(center.x() - size/2.f), std::floor(center.y() - size/2.f)); @@ -349,7 +365,7 @@ namespace MWRender { if (std::find(cell->mMovedRefs.begin(), cell->mMovedRefs.end(), ref.mRefNum) != cell->mMovedRefs.end()) continue; int type = store.findStatic(Misc::StringUtils::lowerCase(ref.mRefID)); - if (!typeFilter(type,size>=2)) continue; + if (!typeFilter(type,size>=2,activeGrid)) continue; if (deleted) { refs.erase(ref.mRefNum); continue; } refs[ref.mRefNum] = ref; } @@ -365,7 +381,7 @@ namespace MWRender bool deleted = it->second; if (deleted) { refs.erase(ref.mRefNum); continue; } int type = store.findStatic(Misc::StringUtils::lowerCase(ref.mRefID)); - if (!typeFilter(type,size>=2)) continue; + if (!typeFilter(type,size>=2,activeGrid)) continue; refs[ref.mRefNum] = ref; } } @@ -387,6 +403,7 @@ namespace MWRender }; typedef std::map, InstanceList> NodeMap; NodeMap nodes; + osg::ref_ptr refnumSet = activeGrid ? new RefnumSet : nullptr; AnalyzeVisitor analyzeVisitor; float minSize = mMinSize; if (mMinSizeMergeFactor) @@ -443,6 +460,9 @@ namespace MWRender continue; } + if (activeGrid && cnode->getNumChildrenRequiringUpdateTraversal() > 0) + continue; + auto emplaced = nodes.emplace(cnode, InstanceList()); if (emplaced.second) { @@ -453,6 +473,9 @@ namespace MWRender else analyzeVisitor.addInstance(emplaced.first->second.mAnalyzeResult); emplaced.first->second.mInstances.push_back(&ref); + + if (activeGrid) + refnumSet->mRefnums.insert(pair.first); } osg::ref_ptr group = new osg::Group; @@ -566,7 +589,13 @@ namespace MWRender group->getBound(); group->setNodeMask(Mask_Static); - group->getOrCreateUserDataContainer()->addUserObject(templateRefs); + osg::UserDataContainer* udc = group->getOrCreateUserDataContainer(); + if (activeGrid) + { + udc->addUserObject(refnumSet); + group->addCullCallback(new SceneUtil::LightListCallback); + } + udc->addUserObject(templateRefs); return group; } @@ -596,7 +625,7 @@ namespace MWRender bool ObjectPaging::enableObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, bool enabled) { - if (!typeFilter(type, false)) + if (!typeFilter(type, false, false)) return false; { @@ -624,6 +653,35 @@ namespace MWRender mCache->clear(); } + struct GetRefnumsFunctor + { + GetRefnumsFunctor(std::set& output) : mOutput(output) {} + void operator()(MWRender::ChunkId chunkId, osg::Object* obj) + { + if (!std::get<2>(chunkId)) return; + const osg::Vec2f& center = std::get<0>(chunkId); + bool activeGrid = (center.x() > mActiveGrid.x() || center.y() > mActiveGrid.y() || center.x() < mActiveGrid.z() || center.y() < mActiveGrid.w()); + if (!activeGrid) return; + + osg::UserDataContainer* udc = obj->getUserDataContainer(); + if (udc && udc->getNumUserObjects()) + { + RefnumSet* refnums = dynamic_cast(udc->getUserObject(0)); + if (!refnums) return; + mOutput.insert(refnums->mRefnums.begin(), refnums->mRefnums.end()); + } + } + osg::Vec4i mActiveGrid; + std::set& mOutput; + }; + + void ObjectPaging::getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out) + { + GetRefnumsFunctor grf(out); + grf.mActiveGrid = activeGrid; + mCache->call(grf); + } + void ObjectPaging::reportStats(unsigned int frameNumber, osg::Stats *stats) const { stats->setAttribute(frameNumber, "Object Chunk", mCache->getCacheSize()); diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index 93423f21e8..79591dcc41 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -19,7 +19,7 @@ namespace MWWorld namespace MWRender { - typedef std::tuple ChunkId; // Center, Size + typedef std::tuple ChunkId; // Center, Size, ActiveGrid class ObjectPaging : public Resource::GenericResourceManager, public Terrain::QuadTreeWorld::ChunkManager { @@ -27,9 +27,9 @@ namespace MWRender ObjectPaging(Resource::SceneManager* sceneManager); ~ObjectPaging() = default; - osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool far, const osg::Vec3f& viewPoint, bool compile) override; + osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) override; - osg::ref_ptr createChunk(float size, const osg::Vec2f& center, const osg::Vec3f& viewPoint, bool compile); + osg::ref_ptr createChunk(float size, const osg::Vec2f& center, bool activeGrid, const osg::Vec3f& viewPoint, bool compile); virtual unsigned int getNodeMask() override; @@ -40,8 +40,11 @@ namespace MWRender void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; + void getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out); + private: Resource::SceneManager* mSceneManager; + bool mActiveGrid; bool mDebugBatches; float mMergeFactor; float mMinSize; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 569f40483c..5523a69369 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1492,4 +1492,9 @@ namespace MWRender } return false; } + void RenderingManager::getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out) + { + if (mObjectPaging) + mObjectPaging->getPagedRefnums(activeGrid, out); + } } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b45e3c8dc8..3082866c43 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -242,6 +242,7 @@ namespace MWRender void setActiveGrid(const osg::Vec4i &grid); bool pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled); + void getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out); private: void updateProjectionMatrix(); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 4280e1e681..eb48424c51 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -450,13 +450,13 @@ namespace MWWorld } } - void CellPreloader::abortTerrainPreloadExcept(const osg::Vec3f& exceptPos) + void CellPreloader::abortTerrainPreloadExcept(const CellPreloader::PositionCellGrid& exceptPos) { if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone()) { const float resetThreshold = ESM::Land::REAL_SIZE; for (auto pos : mTerrainPreloadPositions) - if ((pos.first-exceptPos).length2() < resetThreshold*resetThreshold) + if ((pos.first-exceptPos.first).length2() < resetThreshold*resetThreshold && pos.second == exceptPos.second) return; mTerrainPreloadItem->abort(); mTerrainPreloadItem->waitTillDone(); diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index c170787357..98e173f175 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -73,7 +73,7 @@ namespace MWWorld void setTerrainPreloadPositions(const std::vector& positions); bool getTerrainPreloadInProgress(int& progress, int& progressRange, double timestamp); - void abortTerrainPreloadExcept(const osg::Vec3f& exceptPos); + void abortTerrainPreloadExcept(const PositionCellGrid &exceptPos); private: Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 36f877bee2..bd9a92daee 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ namespace } void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, - MWRender::RenderingManager& rendering) + MWRender::RenderingManager& rendering, std::set& pagedRefs) { if (ptr.getRefData().getBaseNode() || physics.getActor(ptr)) { @@ -104,7 +105,11 @@ namespace if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player - ptr.getClass().insertObjectRendering(ptr, model, rendering); + const ESM::RefNum& refnum = ptr.getCellRef().getRefNum(); + if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end()) + ptr.getClass().insertObjectRendering(ptr, model, rendering); + else + ptr.getRefData().setBaseNode(new SceneUtil::PositionAttitudeTransform); // FIXME remove this when physics code is fixed not to depend on basenode setNodeRotation(ptr, rendering, RotationOrder::direct); ptr.getClass().insertObject (ptr, model, physics); @@ -498,18 +503,14 @@ namespace MWWorld osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter); if (newCell != mCurrentGridCenter) + { + preloadTerrain(pos); changeCellGrid(newCell.x(), newCell.y()); + } } void Scene::changeCellGrid (int playerCellX, int playerCellY, bool changeEvent) { - Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); - Loading::ScopedLoad load(loadingListener); - - int messagesCount = MWBase::Environment::get().getWindowManager()->getMessagesCount(); - std::string loadingExteriorText = "#{sLoadingMessage3}"; - loadingListener->setLabel(loadingExteriorText, false, messagesCount > 0); - CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) { @@ -526,6 +527,14 @@ namespace MWWorld unloadCell (active++); } + mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); + osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); + mRendering.setActiveGrid(newGrid); + + mPagedRefs.clear(); + checkTerrainLoaded(); + mRendering.getPagedRefnums(newGrid, mPagedRefs); + std::size_t refsToLoad = 0; std::vector> cellsPositionsToLoad; // get the number of refs to load @@ -554,6 +563,11 @@ namespace MWWorld } } + Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + Loading::ScopedLoad load(loadingListener); + int messagesCount = MWBase::Environment::get().getWindowManager()->getMessagesCount(); + std::string loadingExteriorText = "#{sLoadingMessage3}"; + loadingListener->setLabel(loadingExteriorText, false, messagesCount > 0); loadingListener->setProgressRange(refsToLoad); const auto getDistanceToPlayerCell = [&] (const std::pair& cellPosition) @@ -601,9 +615,6 @@ namespace MWWorld CellStore* current = MWBase::Environment::get().getWorld()->getExterior(playerCellX, playerCellY); MWBase::Environment::get().getWindowManager()->changeCell(current); - mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); - mRendering.setActiveGrid(gridCenterToBounds(mCurrentGridCenter)); - if (changeEvent) mCellChanged = true; } @@ -820,6 +831,7 @@ namespace MWWorld loadingListener->setProgressRange(cell->count()); // Load cell. + mPagedRefs.clear(); loadCell (cell, loadingListener, changeEvent); changePlayerCell(cell, position, adjustPlayerPos); @@ -850,14 +862,12 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); preloadTerrain(position.asVec3()); - + checkTerrainLoaded(); changeCellGrid(x, y, changeEvent); CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); - checkTerrainLoaded(); - if (changeEvent) MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); } @@ -899,7 +909,7 @@ namespace MWWorld { InsertVisitor insertVisitor (cell, *loadingListener, test); cell.forEach (insertVisitor); - insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering); }); + insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs); }); insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); }); // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order @@ -911,7 +921,7 @@ namespace MWWorld { try { - addObject(ptr, *mPhysics, mRendering); + addObject(ptr, *mPhysics, mRendering, mPagedRefs); addObject(ptr, *mPhysics, mNavigator); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); @@ -943,6 +953,8 @@ namespace MWWorld mRendering.removeObject (ptr); if (ptr.getClass().isActor()) mRendering.removeWaterRippleEmitter(ptr); + ptr.getRefData().setBaseNode(nullptr); + mPagedRefs.erase(ptr.getCellRef().getRefNum()); } bool Scene::isCellActive(const CellStore &cell) @@ -1129,9 +1141,9 @@ namespace MWWorld void Scene::preloadTerrain(const osg::Vec3f &pos) { - mPreloader->abortTerrainPreloadExcept(pos); std::vector vec; vec.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); + mPreloader->abortTerrainPreloadExcept(vec[0]); mPreloader->setTerrainPreloadPositions(vec); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 5727f13919..b7aeafbfec 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -88,6 +88,8 @@ namespace MWWorld osg::Vec3f mLastPlayerPos; + std::set mPagedRefs; + void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false); osg::Vec2i mCurrentGridCenter; diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 1f5a3e4b3c..8f47986df7 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -108,24 +108,20 @@ void QuadTreeNode::initNeighbours() getChild(i)->initNeighbours(); } -void QuadTreeNode::traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback, float maxDist) +void QuadTreeNode::traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback) { if (!hasValidBounds()) return; - - float dist = distance(viewPoint); - if (dist > maxDist) + LodCallback::ReturnValue lodResult = lodCallback->isSufficientDetail(this, distance(viewPoint)); + if (lodResult == LodCallback::StopTraversal) return; - - bool stopTraversal = (lodCallback->isSufficientDetail(this, dist)) || !getNumChildren(); - - if (stopTraversal) - vd->add(this); - else + else if (lodResult == LodCallback::Deeper && getNumChildren()) { for (unsigned int i=0; itraverseNodes(vd, viewPoint, lodCallback, maxDist); + getChild(i)->traverseNodes(vd, viewPoint, lodCallback); } + else + vd->add(this); } void QuadTreeNode::intersect(ViewData* vd, TerrainLineIntersector& intersector) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 147ca8c8a8..183b5e07ae 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -50,7 +50,13 @@ namespace Terrain public: virtual ~LodCallback() {} - virtual bool isSufficientDetail(QuadTreeNode *node, float dist) = 0; + enum ReturnValue + { + Deeper, + StopTraversal, + StopTraversalAndUse + }; + virtual ReturnValue isSufficientDetail(QuadTreeNode *node, float dist) = 0; }; class ViewData; @@ -97,7 +103,7 @@ namespace Terrain const osg::Vec2f& getCenter() const; /// Traverse nodes according to LOD selection. - void traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback, float maxDist); + void traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback); /// Adds all leaf nodes which intersect the line from start to end void intersect(ViewData* vd, TerrainLineIntersector& intersector); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index c7544dbe29..78d8835b58 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -53,34 +53,40 @@ namespace Terrain class DefaultLodCallback : public LodCallback { public: - DefaultLodCallback(float factor, float minSize, const osg::Vec4i& grid) + DefaultLodCallback(float factor, float minSize, float viewDistance, const osg::Vec4i& grid) : mFactor(factor) , mMinSize(minSize) + , mViewDistance(viewDistance) , mActiveGrid(grid) { } - virtual bool isSufficientDetail(QuadTreeNode* node, float dist) + virtual ReturnValue isSufficientDetail(QuadTreeNode* node, float dist) { - int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); - int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize*mFactor))); - + const osg::Vec2f& center = node->getCenter(); + bool activeGrid = (center.x() > mActiveGrid.x() && center.y() > mActiveGrid.y() && center.x() < mActiveGrid.z() && center.y() < mActiveGrid.w()); + if (dist > mViewDistance && !activeGrid) // for Scene<->ObjectPaging sync the activegrid must remain loaded + return StopTraversal; if (node->getSize()>1) { float halfSize = node->getSize()/2; - const osg::Vec2f& center = node->getCenter(); osg::Vec4i nodeBounds (static_cast(center.x() - halfSize), static_cast(center.y() - halfSize), static_cast(center.x() + halfSize), static_cast(center.y() + halfSize)); bool intersects = (std::max(nodeBounds.x(), mActiveGrid.x()) < std::min(nodeBounds.z(), mActiveGrid.z()) && std::max(nodeBounds.y(), mActiveGrid.y()) < std::min(nodeBounds.w(), mActiveGrid.w())); // to prevent making chunks who will cross the activegrid border if (intersects) - return false; + return Deeper; } - return nativeLodLevel <= lodLevel; + + int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); + int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize*mFactor))); + + return nativeLodLevel <= lodLevel ? StopTraversalAndUse : Deeper; } private: float mFactor; float mMinSize; + float mViewDistance; osg::Vec4i mActiveGrid; }; @@ -330,11 +336,11 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, f pat->setPosition(osg::Vec3f(entry.mNode->getCenter().x()*cellWorldSize, entry.mNode->getCenter().y()*cellWorldSize, 0.f)); const osg::Vec2f& center = entry.mNode->getCenter(); - bool far = (center.x() <= gridbounds.x() || center.y() <= gridbounds.y() || center.x() >= gridbounds.z() || center.y() >= gridbounds.w()); + bool activeGrid = (center.x() > gridbounds.x() && center.y() > gridbounds.y() && center.x() < gridbounds.z() && center.y() < gridbounds.w()); for (QuadTreeWorld::ChunkManager* m : chunkManagers) { - osg::ref_ptr n = m->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags, far, vd->getViewPoint(), compile); + osg::ref_ptr n = m->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags, activeGrid, vd->getViewPoint(), compile); if (n) pat->addChild(n); } entry.mRenderingNode = pat; @@ -428,9 +434,8 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) vd->reset(); if (isCullVisitor) { - osgUtil::CullVisitor* cv = static_cast(&nv); - DefaultLodCallback lodCallback(mLodFactor, MIN_SIZE, mActiveGrid); - mRootNode->traverseNodes(vd, cv->getViewPoint(), &lodCallback, mViewDistance); + DefaultLodCallback lodCallback(mLodFactor, MIN_SIZE, mViewDistance, mActiveGrid); + mRootNode->traverseNodes(vd, nv.getViewPoint(), &lodCallback); } else { @@ -515,8 +520,8 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg:: ViewData* vd = static_cast(view); vd->setViewPoint(viewPoint); vd->setActiveGrid(grid); - DefaultLodCallback lodCallback(mLodFactor, MIN_SIZE, grid); - mRootNode->traverseNodes(vd, viewPoint, &lodCallback, mViewDistance); + DefaultLodCallback lodCallback(mLodFactor, MIN_SIZE, mViewDistance, grid); + mRootNode->traverseNodes(vd, viewPoint, &lodCallback); if (!progressTotal) for (unsigned int i=0; igetNumEntries(); ++i) diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 0cd2526dec..7b395bff62 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -15,7 +15,6 @@ namespace Terrain { class RootNode; class ViewDataMap; - class LodCallback; /// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD. class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index b8c151e56b..686d65adc8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -106,9 +106,12 @@ composite map resolution = 512 # Controls the maximum size of composite geometry, should be >= 1.0. With low values there will be many small chunks, with high values - lesser count of bigger chunks. max composite geometry size = 4.0 -# Load far objects on terrain +# Use object paging for non active cells object paging = true +# Use object paging for active cells grid +object paging active grid = true + # Affects the likelyhood of objects being merged. A higher value means merging is more likely and may improve FPS at the cost of memory. object paging merge factor = 250