From 84b8da7a0965a1d38bdc7f1c1a0130d4a05569b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Mar 2016 00:36:35 +0100 Subject: [PATCH] Share the osg::Material on drawables Reduces the number of GL calls / frame by ~4%. --- components/nifosg/nifloader.cpp | 45 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 0ba13d56ff..53b9f33724 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -992,16 +992,7 @@ namespace NifOsg std::vector drawableProps; collectDrawableProperties(nifNode, drawableProps); - applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); - - // Particles don't have normals, so can't be diffuse lit. - osg::Material* mat = static_cast(parentNode->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL)); - if (mat) - { - // NB ignoring diffuse.a() - mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); - mat->setColorMode(osg::Material::AMBIENT); - } + applyDrawableProperties(parentNode, drawableProps, composite, true, animflags, true); // particle system updater (after the emitters and affectors in the scene graph) // I think for correct culling needs to be *before* the ParticleSystem, though osg examples do it the other way @@ -1058,7 +1049,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector drawableProps; collectDrawableProperties(triShape, drawableProps); - applyDrawableProperties(parentNode, drawableProps, composite, !data->colors->empty(), animflags); + applyDrawableProperties(parentNode, drawableProps, composite, !data->colors->empty(), animflags, false); } void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) @@ -1580,8 +1571,26 @@ namespace NifOsg } } + struct CompareMaterial + { + bool operator() (const osg::ref_ptr& left, const osg::ref_ptr& right) const + { + return left->compare(*right) < 0; + } + }; + + osg::Material* shareMaterial(osg::Material* mat) + { + typedef std::set, CompareMaterial> MatCache; + static MatCache mats; + MatCache::iterator found = mats.find(mat); + if (found == mats.end()) + found = mats.insert(mat).first; + return *found; + } + void applyDrawableProperties(osg::Node* node, const std::vector& properties, SceneUtil::CompositeStateSetUpdater* composite, - bool hasVertexColors, int animflags) + bool hasVertexColors, int animflags, bool particleMaterial) { osg::StateSet* stateset = node->getOrCreateStateSet(); @@ -1678,6 +1687,18 @@ namespace NifOsg if (specFlags == 0) mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f,0.f,0.f,0.f)); + // Particles don't have normals, so can't be diffuse lit. + if (particleMaterial) + { + // NB ignoring diffuse.a() + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + mat->setColorMode(osg::Material::AMBIENT); + } + + // TODO: this could be replaced by a more generic mechanism of sharing any type of State Attribute + // apply only for Materials for now + mat = shareMaterial(mat); + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); }