From 712107de2da596aad598bf97eb6d18dc68708100 Mon Sep 17 00:00:00 2001 From: "glassmancody.info" Date: Thu, 10 Feb 2022 11:59:49 -0800 Subject: [PATCH] nisortadjust support --- CHANGELOG.md | 1 + components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 3 +- components/nifosg/nifloader.cpp | 94 +++++++++++++++++++++++++++++---- 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b26d758847..ccdfec178a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ Feature #6443: NiStencilProperty is not fully supported Feature #6534: Shader-based object texture blending Feature #6592: Missing support for NiTriShape particle emitters + Feature #6600: Support NiSortAdjustNode Task #6201: Remove the "Note: No relevant classes found. No output generated" warnings Task #6264: Remove the old classes in animation.cpp Task #6553: Simplify interpreter instruction registration diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 1a1bbd7217..37fb82dd04 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -153,7 +153,7 @@ static std::map makeFactory() factory["bhkRigidBody"] = {&construct , RC_bhkRigidBody }; factory["bhkRigidBodyT"] = {&construct , RC_bhkRigidBodyT }; factory["BSLightingShaderProperty"] = {&construct , RC_BSLightingShaderProperty }; - factory["NiSortAdjustNode"] = {&construct , RC_NiNode }; + factory["NiSortAdjustNode"] = {&construct , RC_NiSortAdjustNode }; factory["NiClusterAccumulator"] = {&construct , RC_NiClusterAccumulator }; factory["NiAlphaAccumulator"] = {&construct , RC_NiAlphaAccumulator }; return factory; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 937ce1d1e9..2ce1ff0743 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -142,7 +142,8 @@ enum RecordType RC_bhkRigidBodyT, RC_BSLightingShaderProperty, RC_NiClusterAccumulator, - RC_NiAlphaAccumulator + RC_NiAlphaAccumulator, + RC_NiSortAdjustNode }; /// Base class for all records diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 206bbf2092..b61681e04e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -219,6 +219,9 @@ namespace NifOsg bool mHasHerbalismLabel = false; bool mHasStencilProperty = false; + const Nif::NiSortAdjustNode* mPushedSorter = nullptr; + const Nif::NiSortAdjustNode* mLastAppliedNoInheritSorter = nullptr; + // This is used to queue emitters that weren't attached to their node yet. std::vector>> mEmitterQueue; @@ -309,10 +312,6 @@ namespace NifOsg if (mHasHerbalismLabel) created->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel); - // When dealing with stencil buffer, draw order is especially sensitive. Make sure such objects are drawn with traversal order. - if (mHasStencilProperty) - created->getOrCreateStateSet()->setRenderBinDetails(2, "TraversalOrderBin"); - // Attach particle emitters to their nodes which should all be loaded by now. handleQueuedParticleEmitters(created, nif); @@ -597,6 +596,22 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiBSAnimationNode || nifNode->recType == Nif::RC_NiBSParticleNode) animflags = nifNode->flags; + if (nifNode->recType == Nif::RC_NiSortAdjustNode) + { + auto sortNode = static_cast(nifNode); + + if (sortNode->mSubSorter.empty()) + { + Log(Debug::Warning) << "Empty accumulator found in '" << nifNode->recName << "' node " << nifNode->recIndex; + } + else + { + if (mPushedSorter && !mPushedSorter->mSubSorter.empty() && mPushedSorter->mMode != Nif::NiSortAdjustNode::SortingMode_Inherit) + mLastAppliedNoInheritSorter = mPushedSorter; + mPushedSorter = sortNode; + } + } + // Hide collision shapes, but don't skip the subgraph // We still need to animate the hidden bones so the physics system can access them if (nifNode->recType == Nif::RC_RootCollisionNode) @@ -2008,6 +2023,13 @@ namespace NifOsg mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); bool hasMatCtrl = false; + bool hasSortAlpha = false; + osg::StateSet* blendFuncStateSet = nullptr; + + auto setBin_Transparent = [] (osg::StateSet* ss) { ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); }; + auto setBin_BackToFront = [] (osg::StateSet* ss) { ss->setRenderBinDetails(0, "SORT_BACK_TO_FRONT"); }; + auto setBin_Traversal = [] (osg::StateSet* ss) { ss->setRenderBinDetails(2, "TraversalOrderBin"); }; + auto setBin_Inherit = [] (osg::StateSet* ss) { ss->setRenderBinToInherit(); }; int lightmode = 1; float emissiveMult = 1.f; @@ -2085,17 +2107,23 @@ namespace NifOsg bool noSort = (alphaprop->flags>>13)&1; if (!noSort) { - node->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - node->getOrCreateStateSet()->setNestRenderBins(false); + hasSortAlpha = true; + if (!mPushedSorter) + setBin_Transparent(node->getStateSet()); } else - node->getOrCreateStateSet()->setRenderBinToInherit(); + { + if (!mPushedSorter) + setBin_Inherit(node->getStateSet()); + } } else if (osg::StateSet* stateset = node->getStateSet()) { stateset->removeAttribute(osg::StateAttribute::BLENDFUNC); stateset->removeMode(GL_BLEND); - stateset->setRenderBinToInherit(); + blendFuncStateSet = stateset; + if (!mPushedSorter) + blendFuncStateSet->setRenderBinToInherit(); } if((alphaprop->flags>>9)&1) @@ -2158,7 +2186,10 @@ namespace NifOsg mat->setColorMode(osg::Material::OFF); } - if (!hasMatCtrl && mat->getColorMode() == osg::Material::OFF + if (!mPushedSorter && !hasSortAlpha && mHasStencilProperty) + setBin_Traversal(node->getOrCreateStateSet()); + + if (!mPushedSorter && !hasMatCtrl && mat->getColorMode() == osg::Material::OFF && mat->getEmission(osg::Material::FRONT_AND_BACK) == osg::Vec4f(0,0,0,1) && mat->getDiffuse(osg::Material::FRONT_AND_BACK) == osg::Vec4f(1,1,1,1) && mat->getAmbient(osg::Material::FRONT_AND_BACK) == osg::Vec4f(1,1,1,1) @@ -2177,6 +2208,51 @@ namespace NifOsg stateset->addUniform(new osg::Uniform("emissiveMult", emissiveMult)); if (specStrength != 1.f) stateset->addUniform(new osg::Uniform("specStrength", specStrength)); + + if (!mPushedSorter) + return; + + auto assignBin = [&] (int mode, int type) { + if (mode == Nif::NiSortAdjustNode::SortingMode_Off) + { + setBin_Traversal(stateset); + return; + } + + if (type == Nif::RC_NiAlphaAccumulator) + { + if (hasSortAlpha) + setBin_BackToFront(stateset); + else + setBin_Traversal(stateset); + } + else if (type == Nif::RC_NiClusterAccumulator) + setBin_BackToFront(stateset); + else + Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename; + }; + + switch (mPushedSorter->mMode) + { + case Nif::NiSortAdjustNode::SortingMode_Inherit: + { + if (mLastAppliedNoInheritSorter) + assignBin(mLastAppliedNoInheritSorter->mMode, mLastAppliedNoInheritSorter->mSubSorter->recType); + else + assignBin(mPushedSorter->mMode, Nif::RC_NiAlphaAccumulator); + break; + } + case Nif::NiSortAdjustNode::SortingMode_Off: + { + setBin_Traversal(stateset); + break; + } + case Nif::NiSortAdjustNode::SortingMode_Subsort: + { + assignBin(mPushedSorter->mMode, mPushedSorter->mSubSorter->recType); + break; + } + } } };