diff --git a/examples/osgmultitexturecontrol/CMakeLists.txt b/examples/osgmultitexturecontrol/CMakeLists.txt index b8d8fdd34..c3a3483f1 100644 --- a/examples/osgmultitexturecontrol/CMakeLists.txt +++ b/examples/osgmultitexturecontrol/CMakeLists.txt @@ -1,4 +1,5 @@ SET(TARGET_SRC osgmultitexturecontrol.cpp ) +SET(TARGET_ADDED_LIBRARIES osgFX ) #### end var setup ### SETUP_EXAMPLE(osgmultitexturecontrol ) diff --git a/examples/osgmultitexturecontrol/osgmultitexturecontrol.cpp b/examples/osgmultitexturecontrol/osgmultitexturecontrol.cpp index 9cca55e94..a40475dfb 100644 --- a/examples/osgmultitexturecontrol/osgmultitexturecontrol.cpp +++ b/examples/osgmultitexturecontrol/osgmultitexturecontrol.cpp @@ -21,8 +21,7 @@ #include #include -#include -#include +#include #include #include @@ -71,13 +70,112 @@ T* findTopMostNodeOfType(osg::Node* node) return fnotv._foundNode; } +/** Callback used to track the elevation of the camera and update the texture weights in an MultiTextureControl node.*/ +class ElevationLayerBlendingCallback : public osg::NodeCallback +{ + public: + + typedef std::vector Elevations; + + ElevationLayerBlendingCallback(osgFX::MultiTextureControl* mtc, const Elevations& elevations, float animationTime=4.0f): + _previousFrame(-1), + _previousTime(0.0), + _mtc(mtc), + _elevations(elevations), + _animationTime(animationTime) {} + + /** Callback method called by the NodeVisitor when visiting a node.*/ + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (!nv->getFrameStamp() || _previousFrame==nv->getFrameStamp()->getFrameNumber()) + { + // we've already updated for this frame so no need to do it again, just traverse children. + traverse(node,nv); + return; + } + + float deltaTime = 0.01f; + if (_previousFrame!=-1) + { + deltaTime = float(nv->getFrameStamp()->getReferenceTime() - _previousTime); + } + + _previousTime = nv->getFrameStamp()->getReferenceTime(); + _previousFrame = nv->getFrameStamp()->getFrameNumber(); + + double elevation = nv->getViewPoint().z(); + + osg::CoordinateSystemNode* csn = dynamic_cast(node); + if (csn) + { + osg::EllipsoidModel* em = csn->getEllipsoidModel(); + if (em) + { + double X = nv->getViewPoint().x(); + double Y = nv->getViewPoint().y(); + double Z = nv->getViewPoint().z(); + double latitude, longitude; + em->convertXYZToLatLongHeight(X,Y,Z,latitude, longitude, elevation); + } + } + + if (_mtc.valid() && !_elevations.empty()) + { + unsigned int index = _mtc->getNumTextureWeights()-1; + for(unsigned int i=0; i<_elevations.size(); ++i) + { + if (elevation>_elevations[i]) + { + index = i; + break; + } + } + + float delta = std::min(deltaTime/_animationTime, 1.0f); + + for(unsigned int i=0; i<_mtc->getNumTextureWeights(); ++i) + { + float currentValue = _mtc->getTextureWeight(i); + float desiredValue = (i==index) ? 1.0f : 0.0f; + if (desiredValue != currentValue) + { + if (currentValuesetTextureWeight(i, desiredValue); + } + } + + } + + traverse(node,nv); + } + + int _previousFrame; + double _previousTime; + float _animationTime; + osg::observer_ptr _mtc; + Elevations _elevations; +}; + + int main( int argc, char **argv ) { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // construct the viewer. - osgViewer::Viewer viewer; + osgViewer::Viewer viewer(arguments); + + // quick hack to work around threading issue with osgFX::MultiTextureControl node's updating of + // its StateAttributes. + viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded); // load the nodes from the commandline arguments. osg::Node* rootnode = osgDB::readNodeFiles(arguments); @@ -89,16 +187,34 @@ int main( int argc, char **argv ) } osg::CoordinateSystemNode* csn = findTopMostNodeOfType(rootnode); - if (csn) - { - osg::notify(osg::NOTICE)<<"Found CSN"<(rootnode); if (mtc) { - osg::notify(osg::NOTICE)<<"Found MTC "<getNumTextureWeights(); } + + if (numLayers<2) + { + osg::notify(osg::NOTICE)<<"Warning: scene must have MultiTextureControl node with at least 2 texture units defined."<setCullCallback(elbc); + else if (mtc) mtc->setCullCallback(elbc); + else rootnode->setCullCallback(elbc); // add terrain manipulator viewer.setCameraManipulator(new osgGA::TerrainManipulator);