From ad46ff7a98fb2bd201e9309b76400f3a7fe61d4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Jun 2015 02:06:04 +0200 Subject: [PATCH] Remove redundant Transform nodes for TriShapes/ParticleSystems with an identity transform --- components/nif/niftypes.hpp | 15 +++++++++++++++ components/nifosg/nifloader.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index d951801452..5827448fdf 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -42,6 +42,15 @@ struct Matrix3 for (int j=0;j<3;++j) mValues[i][j] = (i==j) ? 1.f : 0.f; } + + bool isIdentity() const + { + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + if ((i==j) != (mValues[i][j] == 1)) + return false; + return true; + } }; struct Transformation @@ -62,6 +71,12 @@ struct Transformation return transform; } + bool isIdentity() const + { + return pos == osg::Vec3f(0,0,0) + && rotation.isIdentity() && scale == 1.f; + } + static const Transformation& getIdentity() { static const Transformation identity = { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7aec3385e3..7139bbcef8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -376,6 +376,32 @@ namespace NifOsg toSetup->setFunction(boost::shared_ptr(new ControllerFunction(ctrl))); } + void optimize (const Nif::Node* nifNode, osg::Group* node, bool skipMeshes) + { + // For nodes with an identity transform, remove the redundant Transform node + if (node->getDataVariance() == osg::Object::STATIC + // For TriShapes, we can only collapse the node, but not completely remove it, + // if the link to animated collision shapes is supposed to stay intact. + && (nifNode->recType != Nif::RC_NiTriShape || !skipMeshes)) + { + if (node->getNumParents() && nifNode->trafo.isIdentity()) + { + osg::Group* parent = node->getParent(0); + osg::Node* child = node->getChild(0); + child->setUpdateCallback(node->getUpdateCallback()); + child->setStateSet(node->getStateSet()); + child->setName(node->getName()); + // make sure to copy the UserDataContainer with the record index, so that connections to an animated collision shape don't break + child->setUserDataContainer(node->getUserDataContainer()); + parent->addChild(child); + node->removeChild(child); + parent->removeChild(node); + } + } + // For NiTriShapes *with* a valid transform, perhaps we could apply the transform to the vertices. + // Need to make sure that won't break transparency sorting. Check what the original engine is doing? + } + osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, std::map boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -490,9 +516,15 @@ namespace NifOsg if (composite->getNumControllers() > 0) transformNode->addUpdateCallback(composite); + + // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). + // We can take advantage of this constraint for optimizations later. if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); + // Optimization pass + optimize(nifNode, transformNode, skipMeshes); + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) {