diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 064d3aa35..4217c4714 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -105,6 +105,7 @@ namespace MWRender bool mOptimizeBillboards = true; float mSqrDistance = 0.f; osg::Vec3f mViewVector; + osg::Node::NodeMask mCopyMask = ~0u; mutable std::vector mNodePath; void copy(const osg::Node* toCopy, osg::Group* attachTo) @@ -121,6 +122,9 @@ namespace MWRender osg::Node* operator() (const osg::Node* node) const override { + if (!(node->getNodeMask() & mCopyMask)) + return nullptr; + if (const osg::Drawable* d = node->asDrawable()) return operator()(d); @@ -224,6 +228,9 @@ namespace MWRender } osg::Drawable* operator() (const osg::Drawable* drawable) const override { + if (!(drawable->getNodeMask() & mCopyMask)) + return nullptr; + if (dynamic_cast(drawable)) return nullptr; @@ -261,9 +268,11 @@ namespace MWRender class AnalyzeVisitor : public osg::NodeVisitor { public: - AnalyzeVisitor() + AnalyzeVisitor(osg::Node::NodeMask analyzeMask) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mCurrentStateSet(nullptr) {} + , mCurrentStateSet(nullptr) + , mCurrentDistance(0.f) + , mAnalyzeMask(analyzeMask) {} typedef std::unordered_map StateSetCounter; struct Result @@ -274,12 +283,34 @@ namespace MWRender void apply(osg::Node& node) override { + if (!(node.getNodeMask() & mAnalyzeMask)) + return; + if (node.getStateSet()) mCurrentStateSet = node.getStateSet(); + + if (osg::Switch* sw = node.asSwitch()) + { + for (unsigned int i=0; igetNumChildren(); ++i) + if (sw->getValue(i)) + traverse(*sw->getChild(i)); + return; + } + if (osg::LOD* lod = dynamic_cast(&node)) + { + for (unsigned int i=0; igetNumChildren(); ++i) + if (lod->getMinRange(i) * lod->getMinRange(i) <= mCurrentDistance && mCurrentDistance < lod->getMaxRange(i) * lod->getMaxRange(i)) + traverse(*lod->getChild(i)); + return; + } + traverse(node); } void apply(osg::Geometry& geom) override { + if (!(geom.getNodeMask() & mAnalyzeMask)) + return; + if (osg::Array* array = geom.getVertexArray()) mResult.mNumVerts += array->getNumElements(); @@ -313,6 +344,8 @@ namespace MWRender Result mResult; osg::StateSet* mCurrentStateSet; StateSetCounter mGlobalStateSetCounter; + float mCurrentDistance; + osg::Node::NodeMask mAnalyzeMask; }; class DebugVisitor : public osg::NodeVisitor @@ -438,7 +471,14 @@ namespace MWRender typedef std::map, InstanceList> NodeMap; NodeMap nodes; osg::ref_ptr refnumSet = activeGrid ? new RefnumSet : nullptr; - AnalyzeVisitor analyzeVisitor; + + // Mask_UpdateVisitor is used in such cases in NIF loader: + // 1. For collision nodes, which is not supposed to be rendered. + // 2. For nodes masked via Flag_Hidden (VisController can change this flag value at runtime). + // Since ObjectPaging does not handle VisController, we can just ignore both types of nodes. + constexpr auto copyMask = ~Mask_UpdateVisitor; + + AnalyzeVisitor analyzeVisitor(copyMask); float minSize = mMinSize; if (mMinSizeMergeFactor) minSize *= mMinSizeMergeFactor; @@ -508,6 +548,7 @@ namespace MWRender continue; } + analyzeVisitor.mCurrentDistance = dSqr; auto emplaced = nodes.emplace(cnode, InstanceList()); if (emplaced.second) { @@ -525,6 +566,7 @@ namespace MWRender osg::ref_ptr templateRefs = new Resource::TemplateMultiRef; osgUtil::StateToCompile stateToCompile(0, nullptr); CopyOp copyop; + copyop.mCopyMask = copyMask; for (const auto& pair : nodes) { const osg::Node* cnode = pair.first;