itr != end;
++itr)
techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
+
+ generator = rhs.generator;
}
// Assume that the last technique is always valid.
return pass;
}
+int Effect::getGenerator(Effect::Generator what) const
+{
+ std::map<Generator,int>::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)
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, int> generator; // What is generated into which attribute location
+
std::vector<osg::ref_ptr<Technique> > techniques;
SGPropertyNode_ptr root;
// Pointer to the parameters node, if it exists
#include "Technique.hxx"
#include <osgUtil/CullVisitor>
+#include <osgUtil/TangentSpaceGenerator>
#include <osgDB/Registry>
#include <osgDB/Input>
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<osgUtil::TangentSpaceGenerator> 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<const EffectGeode&>(obj);
typedef DrawableList::iterator DrawablesIterator;
DrawablesIterator drawablesBegin() { return _drawables.begin(); }
DrawablesIterator drawablesEnd() { return _drawables.end(); }
+ void runGenerators(osg::Geometry *geometry);
private:
osg::ref_ptr<Effect> _effect;
};
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;
= 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 " <<
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<OpenThreads::ReentrantMutex>
ref_ptr<SGSceneUserData> 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<osg::Geometry*>(drawable);
+ if(geom) eg->runGenerators(geom);
+ }
}
pushResultNode(&geode, eg);
geode->setName("Ocean tile");
geode->setEffect(effect);
geode->addDrawable(geometry);
+ geode->runGenerators(geometry);
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setName("Ocean");
if (mat)
eg->setEffect(mat->get_effect());
eg->addDrawable(geometry);
+ eg->runGenerators(geometry); // Generate extra data needed by effect
if (group)
group->addChild(eg);
}