From 63fe02b1ba5a5618afa5ef01b01e87f0c87ae601 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Apr 2020 15:50:50 +0300 Subject: [PATCH 1/2] CollisionSwitch and Switch/LOD node fixes Properly apply transformations to both switch and LOD nodes Allow both NiSwitchNode and NiLODNode to be the root node Properly add CollisionSwitch into the scene graph --- components/nifosg/nifloader.cpp | 38 ++++++++++++++++++++---------- components/sceneutil/serialize.cpp | 1 + 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a3972b0e21..e49e672d2b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -170,6 +170,17 @@ namespace NifOsg class CollisionSwitch : public osg::MatrixTransform { public: + CollisionSwitch() : osg::MatrixTransform() + { + } + + CollisionSwitch(const CollisionSwitch& copy, const osg::CopyOp& copyop) + : osg::MatrixTransform(copy, copyop) + { + } + + META_Node(NifOsg, CollisionSwitch) + CollisionSwitch(const osg::Matrixf& transformations, bool enabled) : osg::MatrixTransform(transformations) { setEnabled(enabled); @@ -472,17 +483,8 @@ namespace NifOsg osg::ref_ptr node; osg::Object::DataVariance dataVariance = osg::Object::UNSPECIFIED; - // TODO: it is unclear how to handle transformations of LOD nodes and controllers for them. switch (nifNode->recType) { - case Nif::RC_NiLODNode: - { - const Nif::NiLODNode* niLodNode = static_cast(nifNode); - node = handleLodNode(niLodNode); - dataVariance = osg::Object::DYNAMIC; - break; - } - case Nif::RC_NiSwitchNode: case Nif::RC_NiAutoNormalParticles: case Nif::RC_NiRotatingParticles: // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. @@ -663,6 +665,11 @@ namespace NifOsg && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) handleNodeControllers(nifNode, static_cast(node.get()), animflags); + // LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations properly + // and we need to attach their children to the osg::LOD/osg::Switch nodes + // but we must return that transform to the caller of handleNode instead of the actual LOD/Switch nodes. + osg::ref_ptr currentNode = node; + if (nifNode->recType == Nif::RC_NiSwitchNode) { const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); @@ -673,7 +680,14 @@ namespace NifOsg else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel)) rootNode->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel); - node = switchNode; + currentNode = switchNode; + } + else if (nifNode->recType == Nif::RC_NiLODNode) + { + const Nif::NiLODNode* niLodNode = static_cast(nifNode); + osg::ref_ptr lodNode = handleLodNode(niLodNode); + node->addChild(lodNode); + currentNode = lodNode; } const Nif::NiNode *ninode = dynamic_cast(nifNode); @@ -683,14 +697,14 @@ namespace NifOsg for (size_t i = 0; i < effects.length(); ++i) { if (!effects[i].empty()) - handleEffect(effects[i].getPtr(), node, imageManager); + handleEffect(effects[i].getPtr(), currentNode, imageManager); } const Nif::NodeList &children = ninode->children; for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, skipMeshes, hasMarkers, isAnimated, textKeys, rootNode); + handleNode(children[i].getPtr(), currentNode, imageManager, boundTextures, animflags, skipMeshes, hasMarkers, isAnimated, textKeys, rootNode); } } diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index f84a19876c..60f096a724 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -131,6 +131,7 @@ void registerSerializers() "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry", + "NifOsg::CollisionSwitch", "osgMyGUI::Drawable", "osg::DrawCallback", "osgOQ::ClearQueriesCallback", From 957d2a890f769feee80815c2ce0a310033d5645d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 29 Apr 2020 17:14:50 +0300 Subject: [PATCH 2/2] Ignore empty children of osg::LOD and osg::Switch like in OSG --- components/sceneutil/optimizer.cpp | 21 +++++---------------- components/sceneutil/optimizer.hpp | 2 -- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index e8ebed8686..487126627c 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -735,20 +735,6 @@ bool Optimizer::CombineStaticTransformsVisitor::removeTransforms(osg::Node* node // RemoveEmptyNodes. //////////////////////////////////////////////////////////////////////////// -void Optimizer::RemoveEmptyNodesVisitor::apply(osg::Switch& switchNode) -{ - // We should keep all switch child nodes since they reflect different switch states. - for (unsigned int i=0; i0) @@ -787,8 +773,11 @@ void Optimizer::RemoveEmptyNodesVisitor::removeEmptyNodes() ++pitr) { osg::Group* parent = *pitr; - parent->removeChild(nodeToRemove.get()); - if (parent->getNumChildren()==0 && isOperationPermissibleForObject(parent)) newEmptyGroups.insert(parent); + if (!parent->asSwitch() && !dynamic_cast(parent)) + { + parent->removeChild(nodeToRemove.get()); + if (parent->getNumChildren()==0 && isOperationPermissibleForObject(parent)) newEmptyGroups.insert(parent); + } } } diff --git a/components/sceneutil/optimizer.hpp b/components/sceneutil/optimizer.hpp index 9974e70974..6dd4394d18 100644 --- a/components/sceneutil/optimizer.hpp +++ b/components/sceneutil/optimizer.hpp @@ -321,8 +321,6 @@ class Optimizer BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {} virtual void apply(osg::Group& group); - virtual void apply(osg::LOD& lod); - virtual void apply(osg::Switch& switchNode); void removeEmptyNodes();