// Build the stateset necessary for drawing contours. osg::StateSet* createStateSet( osg::TransferFunction1D* xfer, int unit ) { osg::StateSet* stateSet = new osg::StateSet(); // Create a 1D texture from the transfer function's image. osg::Texture* tex = new osg::Texture1D( xfer->getImage() ); tex->setResizeNonPowerOfTwoHint( false ); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE ); stateSet->setTextureAttributeAndModes( unit, tex, osg::StateAttribute::ON ); // Tell the shader program where to find it. stateSet->getOrCreateUniform( "contour_colorMap", osg::Uniform::SAMPLER_1D )->set( unit ); // Install the shaders. We also bind osgEarth's elevation data attribute, which the // terrain engine automatically generates at the specified location. VirtualProgram* vp = new VirtualProgram(); vp->installDefaultColoringAndLightingShaders(); vp->setFunction( "setupContour", vertexShader, ShaderComp::LOCATION_VERTEX_PRE_LIGHTING ); vp->setFunction( "colorContour", fragmentShader, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); vp->addBindAttribLocation( "osgearth_elevData", osg::Drawable::ATTRIBUTE_6 ); stateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // Install some uniforms that tell the shader the height range of the color map. stateSet->getOrCreateUniform( "contour_xferMin", osg::Uniform::FLOAT )->set( xfer->getMinimum() ); stateSet->getOrCreateUniform( "contour_xferRange", osg::Uniform::FLOAT )->set( xfer->getMaximum() - xfer->getMinimum() ); return stateSet; };
void OSGTerrainEngineNode::installShaders() { // This method installs a default shader setup on the engine node itself. The texture compositor // can then override parts of the program by using a VirtualProgram on the _terrain node. We do // it this way so that the developer has the option of removing this top-level shader program, // replacing it, or migrating it higher up the scene graph if necessary. if ( _texCompositor.valid() && _texCompositor->usesShaderComposition() ) { const ShaderFactory* sf = Registry::instance()->getShaderFactory(); int numLayers = osg::maximum( 1, (int)_update_mapf->imageLayers().size() ); //int numLayers = osg::maximum( 0, (int)_update_mapf->imageLayers().size() ); VirtualProgram* vp = new VirtualProgram(); vp->setName( "engine_osgterrain:EngineNode" ); vp->installDefaultColoringAndLightingShaders(numLayers); getOrCreateStateSet()->setAttributeAndModes( vp, osg::StateAttribute::ON ); } }
void MapNode::init() { // Take a reference to this object so that it doesn't get inadvertently // deleting during startup. It is possible that during startup, a driver // will load that will take a reference to the MapNode (like in a // ModelSource node operation) and we don't want that deleting the MapNode // out from under us. // This is paired by an unref_nodelete() at the end of this method. this->ref(); // Protect the MapNode from the Optimizer setDataVariance(osg::Object::DYNAMIC); // initialize 0Ls _terrainEngine = 0L; _terrainEngineContainer = 0L; _overlayDecorator = 0L; setName( "osgEarth::MapNode" ); // Since we have global uniforms in the stateset, mark it dynamic so it is immune to // multi-threaded overlap // TODO: do we need this anymore? there are no more global uniforms in here.. gw getOrCreateStateSet()->setDataVariance(osg::Object::DYNAMIC); _modelLayerCallback = new MapModelLayerCallback(this); _maskLayerNode = 0L; _lastNumBlacklistedFilenames = 0; // Set the global proxy settings // TODO: this should probably happen elsewhere, like in the registry? if ( _mapNodeOptions.proxySettings().isSet() ) { HTTPClient::setProxySettings( _mapNodeOptions.proxySettings().get() ); } // establish global driver options. These are OSG reader-writer options that // will make their way to any read* calls down the pipe const osgDB::Options* global_options = _map->getGlobalOptions(); osg::ref_ptr<osgDB::Options> local_options = global_options ? Registry::instance()->cloneOrCreateOptions( global_options ) : NULL; if ( local_options.valid() ) { OE_INFO << LC << "Options string = " << (local_options.valid()? local_options->getOptionString() : "<empty>") << std::endl; } // TODO: not sure why we call this here _map->setGlobalOptions( local_options.get() ); // load and attach the terrain engine, but don't initialize it until we need it const TerrainOptions& terrainOptions = _mapNodeOptions.getTerrainOptions(); _terrainEngine = TerrainEngineNodeFactory::create( _map.get(), terrainOptions ); _terrainEngineInitialized = false; // the engine needs a container so we can set lighting state on the container and // not on the terrain engine itself. Setting the dynamic variance will prevent // an optimizer from collapsing the empty group node. _terrainEngineContainer = new osg::Group(); _terrainEngineContainer->setDataVariance( osg::Object::DYNAMIC ); this->addChild( _terrainEngineContainer ); // initialize terrain-level lighting: if ( terrainOptions.enableLighting().isSet() ) { _terrainEngineContainer->getOrCreateStateSet()->setMode( GL_LIGHTING, terrainOptions.enableLighting().value() ? 1 : 0 ); } if ( _terrainEngine ) { // inform the terrain engine of the map information now so that it can properly // initialize it's CoordinateSystemNode. This is necessary in order to support // manipulators and to set up the texture compositor prior to frame-loop // initialization. _terrainEngine->preInitialize( _map.get(), terrainOptions ); _terrainEngineContainer->addChild( _terrainEngine ); } else { OE_WARN << "FAILED to create a terrain engine for this map" << std::endl; } // make a group for the model layers. // NOTE: for now, we are going to nullify any shader programs that occur above the model // group, since it does not YET support shader composition. Programs defined INSIDE a // model layer will still work OK though. _models = new osg::Group(); _models->setName( "osgEarth::MapNode.modelsGroup" ); addChild( _models.get() ); // make a group for overlay model layers: _overlayModels = new ObserverGroup(); //osg::Group(); _overlayModels->setName( "osgEarth::MapNode.overlayModelsGroup" ); // a decorator for overlay models: _overlayDecorator = new OverlayDecorator(); _overlayDecorator->setOverlayGraphTraversalMask( terrainOptions.secondaryTraversalMask().value() ); if ( _mapNodeOptions.overlayBlending().isSet() ) _overlayDecorator->setOverlayBlending( *_mapNodeOptions.overlayBlending() ); if ( _mapNodeOptions.overlayTextureSize().isSet() ) _overlayDecorator->setTextureSize( *_mapNodeOptions.overlayTextureSize() ); if ( _mapNodeOptions.overlayMipMapping().isSet() ) _overlayDecorator->setMipMapping( *_mapNodeOptions.overlayMipMapping() ); addTerrainDecorator( _overlayDecorator ); // install any pre-existing model layers: ModelLayerVector modelLayers; _map->getModelLayers( modelLayers ); int modelLayerIndex = 0; for( ModelLayerVector::const_iterator k = modelLayers.begin(); k != modelLayers.end(); k++, modelLayerIndex++ ) { onModelLayerAdded( k->get(), modelLayerIndex ); } _mapCallback = new MapNodeMapCallbackProxy(this); // install a layer callback for processing further map actions: _map->addMapCallback( _mapCallback.get() ); osg::StateSet* ss = getOrCreateStateSet(); if ( _mapNodeOptions.enableLighting().isSet() ) { ss->setMode( GL_LIGHTING, _mapNodeOptions.enableLighting().value() ? 1 : 0 ); } dirtyBound(); // Install top-level shader programs: if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "MapNode" ); vp->installDefaultColoringAndLightingShaders(); ss->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // register for event traversals so we can deal with blacklisted filenames ADJUST_EVENT_TRAV_COUNT( this, 1 ); // remove the temporary reference. this->unref_nodelete(); }
void OverlayDecorator::initializePerViewData( PerViewData& pvd ) { if ( !_textureUnit.isSet() || !_overlayGraph.valid() ) return; // create the projected texture: osg::Texture2D* projTexture = new osg::Texture2D(); projTexture->setTextureSize( *_textureSize, *_textureSize ); projTexture->setInternalFormat( GL_RGBA ); projTexture->setSourceFormat( GL_RGBA ); projTexture->setSourceType( GL_UNSIGNED_BYTE ); projTexture->setFilter( osg::Texture::MIN_FILTER, _mipmapping? osg::Texture::LINEAR_MIPMAP_LINEAR: osg::Texture::LINEAR ); projTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); projTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); //CLAMP_TO_BORDER ); projTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE ); projTexture->setWrap( osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE ); projTexture->setBorderColor( osg::Vec4(0,0,0,0) ); // set up the RTT camera: pvd._rttCamera = new osg::Camera(); pvd._rttCamera->setClearColor( osg::Vec4f(0,0,0,0) ); pvd._rttCamera->setClearStencil( 0 ); pvd._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); // this ref frame causes the RTT to inherit its viewpoint from above (in order to properly // process PagedLOD's etc. -- it doesn't affect the perspective of the RTT camera though) pvd._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); pvd._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize ); pvd._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); pvd._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER ); pvd._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); pvd._rttCamera->attach( osg::Camera::COLOR_BUFFER, projTexture, 0, 0, _mipmapping ); if (_attachStencil) { // try a depth-packed buffer. failing that, try a normal one.. if the FBO doesn't support // that (which is doesn't on some GPUs like Intel), it will automatically fall back on // a PBUFFER_RTT impl if ( Registry::instance()->getCapabilities().supportsDepthPackedStencilBuffer() ) { #ifdef OSG_GLES2_AVAILABLE pvd._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH24_STENCIL8_EXT ); #else pvd._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH_STENCIL_EXT ); #endif } else { pvd._rttCamera->attach( osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX ); } } osg::StateSet* rttStateSet = pvd._rttCamera->getOrCreateStateSet(); rttStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); // install a new default shader program that replaces anything from above. if ( _useShaders ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "overlay rtt" ); vp->installDefaultColoringAndLightingShaders(); vp->setInheritShaders( false ); rttStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); } if ( _rttBlending ) { //Setup a separate blend function for the alpha components and the RGB components. //Because the destination alpha is initialized to 0 instead of 1 osg::BlendFunc* blendFunc = 0; if (Registry::instance()->getCapabilities().supportsGLSL(1.4f)) { //Blend Func Separate is only available on OpenGL 1.4 and above blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } rttStateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } else { rttStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } // attach the overlay graph to the RTT camera. if ( _overlayGraph.valid() && ( _overlayGraph->getNumParents() == 0 || _overlayGraph->getParent(0) != pvd._rttCamera.get() )) { if ( pvd._rttCamera->getNumChildren() > 0 ) pvd._rttCamera->replaceChild( 0, _overlayGraph.get() ); else pvd._rttCamera->addChild( _overlayGraph.get() ); } // overlay geometry is rendered with no depth testing, and in the order it's found in the // scene graph... until further notice... rttStateSet->setMode(GL_DEPTH_TEST, 0); rttStateSet->setBinName( "TraversalOrderBin" ); // assemble the subgraph stateset: pvd._subgraphStateSet = new osg::StateSet(); pvd._subgraphStateSet->setTextureAttributeAndModes( *_textureUnit, projTexture, osg::StateAttribute::ON ); if ( _useShaders ) { // GPU path initSubgraphShaders( pvd ); } else { // FFP path pvd._texGen = new osg::TexGen(); pvd._texGen->setMode( osg::TexGen::EYE_LINEAR ); pvd._subgraphStateSet->setTextureAttributeAndModes( *_textureUnit, pvd._texGen.get(), 1 ); osg::TexEnv* env = new osg::TexEnv(); env->setMode( osg::TexEnv::DECAL ); pvd._subgraphStateSet->setTextureAttributeAndModes( *_textureUnit, env, 1 ); } }