From d5757c4fb8605463162f3283b5d84e9913cb6d88 Mon Sep 17 00:00:00 2001 From: fredb Date: Sun, 14 Mar 2010 20:04:41 +0000 Subject: [PATCH] Lauri Peltonen : add the ability to generate tangent vectors for model, terrain or ocean geometry inside the effect file --- simgear/scene/material/Effect.cxx | 9 +++++++++ simgear/scene/material/Effect.hxx | 12 ++++++++++++ simgear/scene/material/EffectGeode.cxx | 26 ++++++++++++++++++++++++++ simgear/scene/material/EffectGeode.hxx | 1 + simgear/scene/material/makeEffect.cxx | 20 +++++++++++++++++++- simgear/scene/model/model.cxx | 10 ++++++++-- simgear/scene/tgdb/SGOceanTile.cxx | 1 + simgear/scene/tgdb/obj.cxx | 1 + 8 files changed, 77 insertions(+), 3 deletions(-) diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index f2bcbcdc..c3976d81 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -98,6 +98,8 @@ Effect::Effect(const Effect& rhs, const CopyOp& copyop) itr != end; ++itr) techniques.push_back(static_cast(copyop(itr->get()))); + + generator = rhs.generator; } // Assume that the last technique is always valid. @@ -110,6 +112,13 @@ StateSet* Effect::getDefaultStateSet() return pass; } +int Effect::getGenerator(Effect::Generator what) const +{ + std::map::const_iterator it = generator.find(what); + if(it == generator.end()) return -1; + else return it->second; +} + // There should always be a valid technique in an effect. Technique* Effect::chooseTechnique(RenderInfo* info) diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx index 0690db3a..59eea81d 100644 --- a/simgear/scene/material/Effect.hxx +++ b/simgear/scene/material/Effect.hxx @@ -80,6 +80,18 @@ public: Effect(const Effect& rhs, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); osg::StateSet* getDefaultStateSet(); + + // Define what needs to be generated for this effect + enum Generator + { + NORMAL, + TANGENT, + BINORMAL + }; + void setGenerator(Generator what, int where) { generator[what] = where; } + int getGenerator(Generator what) const; // Returns -1 if generator should not be used + std::map generator; // What is generated into which attribute location + std::vector > techniques; SGPropertyNode_ptr root; // Pointer to the parameters node, if it exists diff --git a/simgear/scene/material/EffectGeode.cxx b/simgear/scene/material/EffectGeode.cxx index aff9aebc..eac2f156 100644 --- a/simgear/scene/material/EffectGeode.cxx +++ b/simgear/scene/material/EffectGeode.cxx @@ -23,6 +23,7 @@ #include "Technique.hxx" #include +#include #include #include @@ -66,6 +67,31 @@ void EffectGeode::releaseGLObjects(osg::State* state) const Geode::releaseGLObjects(state); } +// Generates tangent space vectors or other data from geom, as defined by effect +void EffectGeode::runGenerators(osg::Geometry *geometry) +{ + if(geometry && _effect.valid()) { + // Generate tangent vectors for the geometry + osg::ref_ptr tsg = new osgUtil::TangentSpaceGenerator; + + // Generating only tangent vector should be enough + // since the binormal is a cross product of normal and tangent + // This saves a bit of memory & memory bandwidth! + int n = _effect->getGenerator(Effect::TANGENT); + tsg->generate(geometry, 0); // 0 is normal_unit, but I have no idea what that is! + if (n != -1 && !geometry->getVertexAttribArray(n)) + geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); + + n = _effect->getGenerator(Effect::BINORMAL); + if (n != -1 && !geometry->getVertexAttribArray(n)) + geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); + + n = _effect->getGenerator(Effect::NORMAL); + if (n != -1 && !geometry->getVertexAttribArray(n)) + geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); + } +} + bool EffectGeode_writeLocalData(const Object& obj, osgDB::Output& fw) { const EffectGeode& eg = static_cast(obj); diff --git a/simgear/scene/material/EffectGeode.hxx b/simgear/scene/material/EffectGeode.hxx index 93c552a3..515b1a0a 100644 --- a/simgear/scene/material/EffectGeode.hxx +++ b/simgear/scene/material/EffectGeode.hxx @@ -37,6 +37,7 @@ public: typedef DrawableList::iterator DrawablesIterator; DrawablesIterator drawablesBegin() { return _drawables.begin(); } DrawablesIterator drawablesEnd() { return _drawables.end(); } + void runGenerators(osg::Geometry *geometry); private: osg::ref_ptr _effect; }; diff --git a/simgear/scene/material/makeEffect.cxx b/simgear/scene/material/makeEffect.cxx index 4ce5841f..dfb7fe97 100644 --- a/simgear/scene/material/makeEffect.cxx +++ b/simgear/scene/material/makeEffect.cxx @@ -205,8 +205,10 @@ Effect* makeEffect(SGPropertyNode* prop, lock(effectMutex); cache = parent->getCache(); itr = cache->find(key); - if (itr != cache->end()) + if (itr != cache->end()) { effect = itr->second.get(); + effect->generator = parent->generator; // Copy the generators + } } if (!effect.valid()) { effect = new Effect; @@ -219,6 +221,7 @@ Effect* makeEffect(SGPropertyNode* prop, = cache->insert(make_pair(key, effect)); if (!irslt.second) effect = irslt.first->second; + effect->generator = parent->generator; // Copy the generators } } else { SG_LOG(SG_INPUT, SG_ALERT, "can't find base effect " << @@ -230,6 +233,21 @@ Effect* makeEffect(SGPropertyNode* prop, effect->root = prop; effect->parametersProp = effect->root->getChild("parameters"); } + const SGPropertyNode *generateProp = prop->getChild("generate"); + if(generateProp) + { + effect->generator.clear(); + + // Effect needs some generated properties, like tangent vectors + const SGPropertyNode *parameter = generateProp->getChild("normal"); + if(parameter) effect->setGenerator(Effect::NORMAL, parameter->getIntValue()); + + parameter = generateProp->getChild("tangent"); + if(parameter) effect->setGenerator(Effect::TANGENT, parameter->getIntValue()); + + parameter = generateProp->getChild("binormal"); + if(parameter) effect->setGenerator(Effect::BINORMAL, parameter->getIntValue()); + } if (realizeTechniques) { try { OpenThreads::ScopedLock diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 1ea486f0..41fe9a30 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -274,8 +274,14 @@ void MakeEffectVisitor::apply(osg::Geode& geode) ref_ptr userData = SGSceneUserData::getSceneUserData(&geode); if (userData.valid()) eg->setUserData(new SGSceneUserData(*userData)); - for (int i = 0; i < geode.getNumDrawables(); ++i) - eg->addDrawable(geode.getDrawable(i)); + for (int i = 0; i < geode.getNumDrawables(); ++i) { + osg::Drawable *drawable = geode.getDrawable(i); + eg->addDrawable(drawable); + + // Generate tangent vectors etc if needed + osg::Geometry *geom = dynamic_cast(drawable); + if(geom) eg->runGenerators(geom); + } } pushResultNode(&geode, eg); diff --git a/simgear/scene/tgdb/SGOceanTile.cxx b/simgear/scene/tgdb/SGOceanTile.cxx index 34a0bba7..337a3103 100644 --- a/simgear/scene/tgdb/SGOceanTile.cxx +++ b/simgear/scene/tgdb/SGOceanTile.cxx @@ -310,6 +310,7 @@ osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib) geode->setName("Ocean tile"); geode->setEffect(effect); geode->addDrawable(geometry); + geode->runGenerators(geometry); osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setName("Ocean"); diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 74b4a071..dec3c6c4 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -382,6 +382,7 @@ struct SGTileGeometryBin { if (mat) eg->setEffect(mat->get_effect()); eg->addDrawable(geometry); + eg->runGenerators(geometry); // Generate extra data needed by effect if (group) group->addChild(eg); }