diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 0d547184c..5438347a1 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -285,6 +285,8 @@ namespace MWRender { mMergeFactor = Settings::Manager::getFloat("object paging merge factor", "Terrain"); mMinSize = Settings::Manager::getFloat("object paging min size", "Terrain"); + mMinSizeMergeFactor = Settings::Manager::getFloat("object paging min size merge factor", "Terrain"); + 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) @@ -358,7 +360,9 @@ namespace MWRender typedef std::map, InstanceList> NodeMap; NodeMap nodes; AnalyzeVisitor analyzeVisitor; - + float minSize = mMinSize; + if (mMinSizeMergeFactor) + minSize *= mMinSizeMergeFactor; for (const auto& pair : refs) { const ESM::CellRef& ref = pair.second; @@ -381,7 +385,7 @@ namespace MWRender SizeCache::iterator found = mSizeCache.find(pair.first); if (found != mSizeCache.end()) { - if (found->second < d*mMinSize) + if (found->second < d*minSize) continue; } } @@ -402,7 +406,7 @@ namespace MWRender osg::ref_ptr cnode = mSceneManager->getTemplate(model, false); float radius = cnode->getBound().radius() * ref.mScale; - if (radius < d*mMinSize) + if (radius < d*minSize) { OpenThreads::ScopedLock lock(mSizeCacheMutex); { @@ -435,23 +439,26 @@ namespace MWRender float mergeBenefit = analyzeVisitor.getMergeBenefit(analyzeResult) * mMergeFactor; bool merge = mergeBenefit > mergeCost; - // add a ref to the original template, to hint to the cache that it's still being used and should be kept in cache - templateRefs->mObjects.push_back(cnode); - - if (pair.second.mNeedCompile) - { - int mode = osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES; - if (!merge) - mode |= osgUtil::GLObjectsVisitor::COMPILE_DISPLAY_LISTS; - stateToCompile._mode = mode; - const_cast(cnode)->accept(stateToCompile); - } + float minSizeMerged = mMinSize; + float factor2 = mergeBenefit > 0 ? std::min(1.f, mergeCost * mMinSizeCostMultiplier / mergeBenefit) : 1; + float minSizeMergeFactor2 = (1-factor2) * mMinSizeMergeFactor + factor2; + if (minSizeMergeFactor2 > 0) + minSizeMerged *= minSizeMergeFactor2; + unsigned int numinstances = 0; for (auto cref : pair.second.mInstances) { const ESM::CellRef& ref = *cref; osg::Vec3f pos = ref.mPos.asVec3(); + if (minSizeMerged != minSize) + { + float d = (viewPoint - pos).length(); + float radius = cnode->getBound().radius() * cref->mScale; + if (radius < d*minSizeMerged) + continue; + } + osg::Matrixf matrix; matrix.preMultTranslate(pos - worldCenter); matrix.preMultRotate( osg::Quat(ref.mPos.rot[2], osg::Vec3f(0,0,-1)) * @@ -474,6 +481,21 @@ namespace MWRender mergeGroup->addChild(trans); else group->addChild(trans); + ++numinstances; + } + if (numinstances > 0) + { + // add a ref to the original template, to hint to the cache that it's still being used and should be kept in cache + templateRefs->mObjects.push_back(cnode); + + if (pair.second.mNeedCompile) + { + int mode = osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES; + if (!merge) + mode |= osgUtil::GLObjectsVisitor::COMPILE_DISPLAY_LISTS; + stateToCompile._mode = mode; + const_cast(cnode)->accept(stateToCompile); + } } } diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index 71a0db996..c85fe3705 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -42,6 +42,8 @@ namespace MWRender Resource::SceneManager* mSceneManager; float mMergeFactor; float mMinSize; + float mMinSizeMergeFactor; + float mMinSizeCostMultiplier; OpenThreads::Mutex mDisabledMutex; std::set mDisabled; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ec5e87016..bb21df73e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -115,6 +115,12 @@ object paging merge factor = 1500 # Cull objects smaller than this size divided by distance object paging min size = 0.01 +# Adjusts 'min size' based on merging decision. Allows inexpensive objects to be rendered from a greater distance. +object paging min size merge factor = 0.6 + +# Controls how inexpensive an object needs to be to utilize 'min size merge factor'. +object paging min size cost multiplier = 4 + [Fog] # If true, use extended fog parameters for distant terrain not controlled by