activegrid paging = 2xfps

Signed-off-by: Bret Curtis <psi29a@gmail.com>
pull/2911/head
bzzt lost a hitlab login 5 years ago committed by Bret Curtis
parent b4af2ac672
commit c7fda6d280

@ -18,6 +18,7 @@
#include <osgParticle/ParticleProcessor>
#include <osgParticle/ParticleSystemUpdater>
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/riggeometry.hpp>
#include <components/settings/settings.hpp>
@ -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<osg::Node> 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<osg::Node> 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<osg::Object> obj = mCache->getRefFromObjectCache(id);
if (obj)
return obj->asNode();
else
{
osg::ref_ptr<osg::Node> node = createChunk(size, center, viewPoint, compile);
osg::ref_ptr<osg::Node> node = createChunk(size, center, activeGrid, viewPoint, compile);
mCache->addEntryToObjectCache(id, node.get());
return node;
}
@ -231,6 +237,15 @@ namespace MWRender
std::vector<osg::ref_ptr<const Object>> mObjects;
};
class RefnumSet : public osg::Object
{
public:
RefnumSet(){}
RefnumSet(const RefnumSet& copy, const osg::CopyOp&) : mRefnums(copy.mRefnums) {}
META_Object(MWRender, RefnumSet)
std::set<ESM::RefNum> mRefnums;
};
class AnalyzeVisitor : public osg::NodeVisitor
{
public:
@ -310,6 +325,7 @@ namespace MWRender
: GenericResourceManager<ChunkId>(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<osg::Node> ObjectPaging::createChunk(float size, const osg::Vec2f& center, const osg::Vec3f& viewPoint, bool compile)
osg::ref_ptr<osg::Node> 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<osg::ref_ptr<const osg::Node>, InstanceList> NodeMap;
NodeMap nodes;
osg::ref_ptr<RefnumSet> 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<osg::Group> 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<ESM::RefNum>& 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<RefnumSet*>(udc->getUserObject(0));
if (!refnums) return;
mOutput.insert(refnums->mRefnums.begin(), refnums->mRefnums.end());
}
}
osg::Vec4i mActiveGrid;
std::set<ESM::RefNum>& mOutput;
};
void ObjectPaging::getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &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());

@ -19,7 +19,7 @@ namespace MWWorld
namespace MWRender
{
typedef std::tuple<osg::Vec2f, float> ChunkId; // Center, Size
typedef std::tuple<osg::Vec2f, float, bool> ChunkId; // Center, Size, ActiveGrid
class ObjectPaging : public Resource::GenericResourceManager<ChunkId>, public Terrain::QuadTreeWorld::ChunkManager
{
@ -27,9 +27,9 @@ namespace MWRender
ObjectPaging(Resource::SceneManager* sceneManager);
~ObjectPaging() = default;
osg::ref_ptr<osg::Node> 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<osg::Node> 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<osg::Node> createChunk(float size, const osg::Vec2f& center, const osg::Vec3f& viewPoint, bool compile);
osg::ref_ptr<osg::Node> 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<ESM::RefNum> &out);
private:
Resource::SceneManager* mSceneManager;
bool mActiveGrid;
bool mDebugBatches;
float mMergeFactor;
float mMinSize;

@ -1492,4 +1492,9 @@ namespace MWRender
}
return false;
}
void RenderingManager::getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out)
{
if (mObjectPaging)
mObjectPaging->getPagedRefnums(activeGrid, out);
}
}

@ -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<ESM::RefNum> &out);
private:
void updateProjectionMatrix();

@ -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();

@ -73,7 +73,7 @@ namespace MWWorld
void setTerrainPreloadPositions(const std::vector<PositionCellGrid>& positions);
bool getTerrainPreloadInProgress(int& progress, int& progressRange, double timestamp);
void abortTerrainPreloadExcept(const osg::Vec3f& exceptPos);
void abortTerrainPreloadExcept(const PositionCellGrid &exceptPos);
private:
Resource::ResourceSystem* mResourceSystem;

@ -13,6 +13,7 @@
#include <components/resource/scenemanager.hpp>
#include <components/resource/bulletshape.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/detournavigator/navigator.hpp>
#include <components/detournavigator/debug.hpp>
#include <components/misc/convert.hpp>
@ -87,7 +88,7 @@ namespace
}
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering)
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& 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<std::pair<int, int>> 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<int, int>& 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<PositionCellGrid> vec;
vec.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos)));
mPreloader->abortTerrainPreloadExcept(vec[0]);
mPreloader->setTerrainPreloadPositions(vec);
}

@ -88,6 +88,8 @@ namespace MWWorld
osg::Vec3f mLastPlayerPos;
std::set<ESM::RefNum> mPagedRefs;
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false);
osg::Vec2i mCurrentGridCenter;

@ -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; i<getNumChildren(); ++i)
getChild(i)->traverseNodes(vd, viewPoint, lodCallback, maxDist);
getChild(i)->traverseNodes(vd, viewPoint, lodCallback);
}
else
vd->add(this);
}
void QuadTreeNode::intersect(ViewData* vd, TerrainLineIntersector& intersector)

@ -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);

@ -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<unsigned int>(node->getSize()/mMinSize));
int lodLevel = Log2(static_cast<unsigned int>(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<int>(center.x() - halfSize), static_cast<int>(center.y() - halfSize), static_cast<int>(center.x() + halfSize), static_cast<int>(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<unsigned int>(node->getSize()/mMinSize));
int lodLevel = Log2(static_cast<unsigned int>(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<osg::Node> n = m->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags, far, vd->getViewPoint(), compile);
osg::ref_ptr<osg::Node> 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<osgUtil::CullVisitor*>(&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<ViewData*>(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; i<vd->getNumEntries(); ++i)

@ -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)

@ -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

Loading…
Cancel
Save