From 4692456a79cf7c7e544d5d63f32848556c00af3d Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Aug 2024 17:46:52 +0100 Subject: [PATCH 1/2] Remove LOD range overlap Should resolve https://gitlab.com/OpenMW/openmw/-/issues/8134 NiLODNode will only render the last child with a compatible range, whereas osg::LOD renders all children that have compatible ranges. There are now meshes in the wild with overlapping ranges, so we need to tidy that up on load. --- components/nifosg/nifloader.cpp | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6ec0fe51e0..e449e6a8a9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -475,10 +475,44 @@ namespace NifOsg lod->setName(niLodNode->mName); lod->setCenterMode(osg::LOD::USER_DEFINED_CENTER); lod->setCenter(niLodNode->mLODCenter); + // NiLODNode only uses the last child with a compatible range, osg::LOD uses all of them + // We must remove overlaps + std::vector> ranges; for (unsigned int i = 0; i < niLodNode->mLODLevels.size(); ++i) { const Nif::NiLODNode::LODRange& range = niLodNode->mLODLevels[i]; - lod->setRange(i, range.mMinRange, range.mMaxRange); + for (auto& rangeVec : ranges) + { + for (auto itr = rangeVec.begin(); itr != rangeVec.end();) + { + if (itr->mMinRange >= range.mMinRange && itr->mMaxRange <= range.mMaxRange) + { + itr = rangeVec.erase(itr); + continue; + } + else if (itr->mMinRange >= range.mMinRange && itr->mMaxRange > range.mMaxRange) + itr->mMinRange = range.mMaxRange; + else if (itr->mMinRange < range.mMinRange && itr->mMaxRange <= range.mMaxRange) + itr->mMaxRange = range.mMinRange; + else if (itr->mMinRange < range.mMinRange && itr->mMaxRange > range.mMaxRange) + { + auto max = itr->mMaxRange; + itr->mMaxRange = range.mMinRange; + itr = rangeVec.emplace(itr + 1, range.mMaxRange, max); + } + ++itr; + } + } + } + size_t childIndex = 0; + for (auto rangeVec : ranges) + { + if (rangeVec.empty()) + lod->removeChild(childIndex); + for (size_t i = 1; i < rangeVec.size(); ++i) + lod->insertChild(childIndex + i, lod->getChild(childIndex)); + for (const auto range : rangeVec) + lod->setRange(childIndex++, range.mMinRange, range.mMaxRange); } lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); return lod; From f17b7a6be86f08beca947c5acc8abd94eb98a3c3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 26 Aug 2024 19:15:53 +0100 Subject: [PATCH 2/2] Remove the easily-fixable bug This line was always supposed to be here, I just forgot to actually type it. --- components/nifosg/nifloader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e449e6a8a9..ae38898950 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -503,6 +503,7 @@ namespace NifOsg ++itr; } } + ranges.emplace_back(std::initializer_list{ range }); } size_t childIndex = 0; for (auto rangeVec : ranges)