void ShaderGenerator::run(osg::Node* graph, const std::string& vpName, StateSetCache* cache) { if ( graph ) { // generate shaders: graph->accept( *this ); // perform GL state sharing optimizeStateSharing( graph, cache ); osg::StateSet* stateset = cloneOrCreateStateSet(graph); // install a blank VP at the top as the default. VirtualProgram* vp = VirtualProgram::get(stateset); if ( !vp ) { vp = VirtualProgram::getOrCreate(stateset); vp->setInheritShaders( true ); vp->setName( vpName ); } } }
void ShaderGenerator::run(osg::Node* graph, StateSetCache* cache) { if ( graph ) { _texImageUnits.clear(); // generate shaders: graph->accept( *this ); // perform GL state sharing if ( cache ) cache->optimize( graph ); osg::StateSet* stateset = graph->getOrCreateStateSet(); // install a blank VP at the top as the default. VirtualProgram* vp = VirtualProgram::get(stateset); if ( !vp ) { vp = VirtualProgram::getOrCreate(stateset); vp->setInheritShaders( true ); vp->setName( _name ); } // apply a uniform for each sampler binding we found. for(std::set<int>::iterator i = _texImageUnits.begin(); i != _texImageUnits.end(); ++i) { std::string name = Stringify() << SAMPLER << *i; stateset->addUniform( new osg::Uniform(name.c_str(), *i) ); } _texImageUnits.clear(); } }
void LODBlending::onInstall(TerrainEngineNode* engine) { if ( engine ) { // need the parent textures for blending. engine->requireParentTextures(); osg::StateSet* stateset = engine->getOrCreateStateSet(); stateset->addUniform( _delayUniform.get() ); stateset->addUniform( _durationUniform.get() ); stateset->addUniform( _vscaleUniform.get() ); VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setName( "osgEarth::Util::LODBlending" ); if ( _blendElevation == true ) { vp->setFunction("oe_lodblend_elevation_vertex", vs_elevation, ShaderComp::LOCATION_VERTEX_MODEL ); } if ( _blendImagery == true ) { vp->setFunction("oe_lodblend_imagery_vertex", vs_imagery, ShaderComp::LOCATION_VERTEX_VIEW); vp->setFunction("oe_lodblend_imagery_fragment", fs_imagery, ShaderComp::LOCATION_FRAGMENT_COLORING); } OE_INFO << LC << "On!\n"; } }
void FogEffect::attach( osg::StateSet* stateSet ) { VirtualProgram* vp = VirtualProgram::getOrCreate( stateSet ); vp->setName("Fog"); Shaders pkg; pkg.load( vp, pkg.Fog_Vertex ); pkg.load( vp, pkg.Fog_Fragment ); _statesets.push_back(stateSet); }
bool ShaderGenerator::processText(const osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement) { // do nothing if there's no GLSL support if ( !_active ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program. If it exists, bail out so that OSG // can use the program already in the graph osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // new state set: replacement = ss ? osg::clone(ss, osg::CopyOp::SHALLOW_COPY) : new osg::StateSet(); // new VP: VirtualProgram* vp = 0L; if ( VirtualProgram::get(replacement.get()) ) vp = osg::clone(VirtualProgram::get(replacement.get()), osg::CopyOp::DEEP_COPY_ALL); else vp = VirtualProgram::getOrCreate(replacement.get()); if ( vp->referenceCount() == 1 ) vp->setName( _name ); std::string vertSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " VERTEX_FUNCTION "(inout vec4 vertexVIEW)\n" "{ \n" INDENT TEX_COORD_TEXT " = gl_MultiTexCoord0;\n" "} \n"; std::string fragSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "uniform sampler2D " SAMPLER_TEXT ";\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " FRAGMENT_FUNCTION "(inout vec4 color)\n" "{ \n" INDENT MEDIUMP "vec4 texel = texture2D(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy);\n" INDENT "color.a *= texel.a; \n" "}\n"; vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); replacement->getOrCreateUniform( SAMPLER_TEXT, osg::Uniform::SAMPLER_2D )->set( 0 ); return replacement.valid(); }
void PhongLightingEffect::attach(osg::StateSet* stateset) { if ( stateset && _supported ) { _statesets.push_back(stateset); VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setName( "osgEarth.PhongLightingEffect" ); vp->setFunction( "oe_phong_vertex", Phong_Vertex, ShaderComp::LOCATION_VERTEX_VIEW, 0.5f ); vp->setFunction( "oe_phong_fragment", Phong_Fragment, ShaderComp::LOCATION_FRAGMENT_LIGHTING, 0.5f); if ( _lightingUniform.valid() ) stateset->addUniform( _lightingUniform.get() ); } }
void OverlayDecorator::initSubgraphShaders( PerViewData& pvd ) { osg::StateSet* set = pvd._subgraphStateSet.get(); VirtualProgram* vp = new VirtualProgram(); vp->setName( "OverlayDecorator subgraph shader" ); set->setAttributeAndModes( vp, osg::StateAttribute::ON ); // sampler for projected texture: set->getOrCreateUniform( "oe_overlay_ProjTex", osg::Uniform::SAMPLER_2D )->set( *_textureUnit ); // the texture projection matrix uniform. pvd._texGenUniform = set->getOrCreateUniform( "oe_overlay_TexGenMatrix", osg::Uniform::FLOAT_MAT4 ); // vertex shader - subgraph std::string vertexSource = Stringify() << "#version " << GLSL_VERSION_STR << "\n" #ifdef OSG_GLES2_AVAILABLE << "precision mediump float;\n" #endif << "uniform mat4 oe_overlay_TexGenMatrix; \n" << "uniform mat4 osg_ViewMatrixInverse; \n" << "varying vec4 osg_TexCoord[" << Registry::capabilities().getMaxGPUTextureCoordSets() << "]; \n" << "void oe_overlay_vertex(void) \n" << "{ \n" << " osg_TexCoord["<< *_textureUnit << "] = oe_overlay_TexGenMatrix * osg_ViewMatrixInverse * gl_ModelViewMatrix * gl_Vertex; \n" << "} \n"; vp->setFunction( "oe_overlay_vertex", vertexSource, ShaderComp::LOCATION_VERTEX_POST_LIGHTING ); // fragment shader - subgraph std::string fragmentSource = Stringify() << "#version " << GLSL_VERSION_STR << "\n" #ifdef OSG_GLES2_AVAILABLE << "precision mediump float;\n" #endif << "uniform sampler2D oe_overlay_ProjTex; \n" << "varying vec4 osg_TexCoord[" << Registry::capabilities().getMaxGPUTextureCoordSets() << "]; \n" << "void oe_overlay_fragment( inout vec4 color ) \n" << "{ \n" << " vec2 texCoord = osg_TexCoord["<< *_textureUnit << "].xy / osg_TexCoord["<< *_textureUnit << "].q; \n" << " vec4 texel = texture2D(oe_overlay_ProjTex, texCoord); \n" << " color = vec4( mix( color.rgb, texel.rgb, texel.a ), color.a); \n" << "} \n"; vp->setFunction( "oe_overlay_fragment", fragmentSource, ShaderComp::LOCATION_FRAGMENT_POST_LIGHTING ); }
void AlphaEffect::install(osg::StateSet* stateset) { if (stateset) { VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); if (vp) { vp->setName( "osgEarth.AlphaEffect" ); Shaders pkg; pkg.load(vp, pkg.AlphaEffectFragment); stateset->addUniform(_alphaUniform.get()); } } }
void OceanCompositor::updateMasterStateSet(osg::StateSet* stateSet, const TextureLayout& layout ) const { VirtualProgram* vp = static_cast<VirtualProgram*>( stateSet->getAttribute(VirtualProgram::SA_TYPE) ); if ( !vp ) { vp = new VirtualProgram(); vp->setName("osgEarth OceanCompositor"); stateSet->setAttributeAndModes( vp, 1 ); } vp->installDefaultLightingShaders(); vp->setShader( "osgearth_vert_setupColoring", new osg::Shader(osg::Shader::VERTEX, source_setupColoring) ); vp->setShader( "osgearth_frag_applyColoring", new osg::Shader(osg::Shader::FRAGMENT, source_applyColoring ) ); }
VirtualProgram* RTTPicker::createRTTProgram() { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth::RTTPicker" ); // Install RTT picker shaders: ShaderPackage pickShaders; pickShaders.add( "RTTPicker.vert.glsl", pickVertexEncode ); pickShaders.add( "RTTPicker.frag.glsl", pickFragment ); pickShaders.loadAll( vp ); // Install shaders and bindings from the ObjectIndex: Registry::objectIndex()->loadShaders( vp ); return vp; }
void OSGTerrainEngineNode::updateTextureCombining() { if ( _texCompositor.valid() ) { int numImageLayers = _update_mapf->imageLayers().size(); osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); if ( _texCompositor->usesShaderComposition() ) { // Creates or updates the shader components that are generated by the texture compositor. // These components reside in the CustomTerrain's stateset, and override the components // installed in the VP on the engine-node's stateset in installShaders(). VirtualProgram* vp = new VirtualProgram() ; vp->setName( "engine_osgterrain:TerrainNode" ); vp->installDefaultColoringShaders(numImageLayers); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // first, update the default shader components based on the new layer count: const ShaderFactory* sf = Registry::instance()->getShaderFactory(); // second, install the per-layer color filter functions. for( int i=0; i<numImageLayers; ++i ) { std::string layerFilterFunc = Stringify() << "osgearth_runColorFilters_" << i; const ColorFilterChain& chain = _update_mapf->getImageLayerAt(i)->getColorFilters(); // install the wrapper function that calls all the filters in turn: vp->setShader( layerFilterFunc, sf->createColorFilterChainFragmentShader(layerFilterFunc, chain) ); // install each of the filter entry points: for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); filter->install( terrainStateSet ); } } } // next, inform the compositor that it needs to update based on a new layer count: _texCompositor->updateMasterStateSet( terrainStateSet ); //, numImageLayers ); } }
void ShaderGenerator::apply(osg::ClipNode& node) { static const char* s_clip_source = "#version " GLSL_VERSION_STR "\n" "void oe_sg_set_clipvertex(inout vec4 vertexVIEW)\n" "{\n" " gl_ClipVertex = vertexVIEW; \n" "}\n"; if ( !_active ) return; VirtualProgram* vp = VirtualProgram::getOrCreate(node.getOrCreateStateSet()); if ( vp->referenceCount() == 1 ) vp->setName( _name ); vp->setFunction( "oe_sg_set_clipvertex", s_clip_source, ShaderComp::LOCATION_VERTEX_VIEW ); apply( static_cast<osg::Group&>(node) ); }
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 ); } }
RexTerrainEngineNode::RexTerrainEngineNode() : TerrainEngineNode ( ), _terrain ( 0L ), _tileCount ( 0 ), _tileCreationTime ( 0.0 ), _batchUpdateInProgress( false ), _refreshRequired ( false ), _stateUpdateRequired ( false ) { // Necessary for pager object data this->setName("osgEarth.RexTerrainEngineNode"); // unique ID for this engine: _uid = Registry::instance()->createUID(); // always require elevation. _requireElevationTextures = true; // install an elevation callback so we can update elevation data _elevationCallback = new ElevationChangedCallback( this ); // static shaders. if ( Registry::capabilities().supportsGLSL() ) { osg::StateSet* stateset = getOrCreateStateSet(); VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); vp->setName("RexTerrainEngineNode"); vp->setIsAbstract(true); // cannot run by itself, requires additional children Shaders package; package.load(vp, package.SDK); } // TODO: replace with a "renderer" object that can return statesets // for different layer types, or something. _imageLayerStateSet = new osg::StateSet(); }
void Text::setFont(osg::ref_ptr<osgText::Font> font) { if (_font.get() == font.get()) return; #if OSG_VERSION_GREATER_OR_EQUAL(3,5,8) osgText::Text::setFont(font); #else static Threading::Mutex mutex; Threading::ScopedMutexLock lock(mutex); osg::StateSet* previousFontStateSet = _font.valid() ? _font->getStateSet() : osgText::Font::getDefaultFont()->getStateSet(); osg::StateSet* newFontStateSet = font.valid() ? font->getStateSet() : osgText::Font::getDefaultFont()->getStateSet(); //if (getStateSet() == previousFontStateSet) { if (newFontStateSet && VirtualProgram::get(newFontStateSet) == 0L) { VirtualProgram* vp = VirtualProgram::getOrCreate(newFontStateSet); vp->setName("osgEarth::Text"); osgEarth::Shaders coreShaders; coreShaders.load(vp, coreShaders.TextLegacy); #if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE) newFontStateSet->setDefine("OSGTEXT_GLYPH_ALPHA_FORMAT_IS_RED"); #endif Lighting::set(newFontStateSet, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED); OE_INFO << LC << "Installed VPs on a font" << std::endl; } setStateSet( newFontStateSet ); } osgText::TextBase::setFont(font); #endif }
// Generates the main shader code for rendering the terrain. void RexTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // everything osg::StateSet* surfaceStateSet = getSurfaceStateSet(); // just the surface // required for multipass tile rendering to work surfaceStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install patch param if we are tessellation on the GPU. if ( _terrainOptions.gpuTessellation() == true ) { #ifdef HAVE_PATCH_PARAMETER terrainStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { Shaders package; VirtualProgram* terrainVP = VirtualProgram::getOrCreate(terrainStateSet); terrainVP->setName( "Rex Terrain" ); package.load(terrainVP, package.ENGINE_VERT_MODEL); //moved to CTOR so it's always available //package.load(terrainVP, package.SDK); bool useTerrainColor = _terrainOptions.color().isSet(); package.define("OE_REX_USE_TERRAIN_COLOR", useTerrainColor); if ( useTerrainColor ) { surfaceStateSet->addUniform(new osg::Uniform("oe_terrain_color", _terrainOptions.color().get())); } bool useBlending = _terrainOptions.enableBlending().get(); package.define("OE_REX_GL_BLENDING", useBlending); bool morphImagery = _terrainOptions.morphImagery().get(); package.define("OE_REX_MORPH_IMAGERY", morphImagery); // Funtions that affect only the terrain surface: VirtualProgram* surfaceVP = VirtualProgram::getOrCreate(surfaceStateSet); surfaceVP->setName("Rex Surface"); // Functions that affect the terrain surface only: package.load(surfaceVP, package.ENGINE_VERT_VIEW); package.load(surfaceVP, package.ENGINE_FRAG); // Normal mapping shaders: if ( this->normalTexturesRequired() ) { package.load(surfaceVP, package.NORMAL_MAP_VERT); package.load(surfaceVP, package.NORMAL_MAP_FRAG); } // Morphing? if (_terrainOptions.morphTerrain() == true || _terrainOptions.morphImagery() == true) { package.define("OE_REX_VERTEX_MORPHING", (_terrainOptions.morphTerrain() == true)); package.load(surfaceVP, package.MORPHING_VERT); } for(LandCoverZones::iterator zone = _landCoverData._zones.begin(); zone != _landCoverData._zones.end(); ++zone) { for(LandCoverBins::iterator bin = zone->_bins.begin(); bin != zone->_bins.end(); ++bin) { osg::StateSet* landCoverStateSet = bin->_binProto->getStateSet(); // enable alpha-to-coverage multisampling for vegetation. landCoverStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, 1); // uniform that communicates the availability of multisampling. landCoverStateSet->addUniform( new osg::Uniform( "oe_terrain_hasMultiSamples", osg::DisplaySettings::instance()->getMultiSamples()) ); landCoverStateSet->setAttributeAndModes( new osg::BlendFunc(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO), osg::StateAttribute::OVERRIDE ); #ifdef HAVE_OSG_PATCH_PARAMETER landCoverStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } } // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_rexEngine_applyFilters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( surfaceStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); surfaceVP->setFunction( "oe_rexEngine_applyFilters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } // Apply uniforms for sampler bindings: OE_DEBUG << LC << "Render Bindings:\n"; for(RenderBindings::const_iterator b = _renderBindings.begin(); b != _renderBindings.end(); ++b) { if ( b->isActive() ) { terrainStateSet->addUniform( new osg::Uniform(b->samplerName().c_str(), b->unit()) ); OE_DEBUG << LC << " > Bound \"" << b->samplerName() << "\" to unit " << b->unit() << "\n"; } } // uniform that controls per-layer opacity terrainStateSet->addUniform( new osg::Uniform("oe_layer_opacity", 1.0f) ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->addUniform( new osg::Uniform("oe_layer_uid", (int)-1 ) ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->addUniform( new osg::Uniform("oe_layer_order", (int)0) ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); terrainStateSet->addUniform(new osg::Uniform("oe_tile_size", (float)_terrainOptions.tileSize().get())); // special object ID that denotes the terrain surface. surfaceStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
void SimpleOceanNode::rebuild() { this->removeChildren( 0, this->getNumChildren() ); if ( _parentMapNode.valid() ) { const MapOptions& parentMapOptions = _parentMapNode->getMap()->getMapOptions(); const MapNodeOptions& parentMapNodeOptions = _parentMapNode->getMapNodeOptions(); // set up the map to "match" the parent map: MapOptions mo; mo.coordSysType() = parentMapOptions.coordSysType(); mo.profile() = _parentMapNode->getMap()->getProfile()->toProfileOptions(); // new data model for the ocean: Map* oceanMap = new Map( mo ); // ditto with the map node options: MapNodeOptions mno; if ( mno.enableLighting().isSet() ) mno.enableLighting() = *mno.enableLighting(); MPTerrainEngineOptions mpoptions; mpoptions.heightFieldSkirtRatio() = 0.0; // don't want to see skirts mpoptions.minLOD() = _options.maxLOD().get(); // weird, I know // so we can the surface from underwater: mpoptions.clusterCulling() = false; // want to see underwater mpoptions.enableBlending() = true; // gotsta blend with the main node mpoptions.color() = _options.baseColor().get(); mno.setTerrainOptions( mpoptions ); // make the ocean's map node: MapNode* oceanMapNode = new MapNode( oceanMap, mno ); // if the caller requested a mask layer, install that now. if ( _options.maskLayer().isSet() ) { if ( !_options.maskLayer()->maxLevel().isSet() ) { // set the max subdivision level if it's not already specified in the // mask layer options: _options.maskLayer()->maxLevel() = *_options.maxLOD(); } // make sure the mask is shared (so we can access it from our shader) // and invisible (so we can't see it) _options.maskLayer()->shared() = true; _options.maskLayer()->visible() = false; ImageLayer* maskLayer = new ImageLayer( "ocean-mask", *_options.maskLayer() ); oceanMap->addImageLayer( maskLayer ); } // otherwise, install a "proxy layer" that will use the elevation data in the map // to determine where the ocean is. This approach is limited in that it cannot // detect the difference between ocean and inland areas that are below sea level. else { // install an "elevation proxy" layer that reads elevation tiles from the // parent map and turns them into encoded images for our shader to use. ImageLayerOptions epo( "ocean-proxy" ); epo.cachePolicy() = CachePolicy::NO_CACHE; //epo.maxLevel() = *_options.maxLOD(); oceanMap->addImageLayer( new ElevationProxyImageLayer(_parentMapNode->getMap(), epo) ); } this->addChild( oceanMapNode ); // set up the shaders. osg::StateSet* ss = this->getOrCreateStateSet(); // install the shaders on the ocean map node. VirtualProgram* vp = VirtualProgram::getOrCreate( ss ); vp->setName( "osgEarth SimpleOcean" ); // use the appropriate shader for the active technique: std::string vertSource = _options.maskLayer().isSet() ? source_vertMask : source_vertProxy; std::string fragSource = _options.maskLayer().isSet() ? source_fragMask : source_fragProxy; vp->setFunction( "oe_ocean_vertex", vertSource, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( "oe_ocean_fragment", fragSource, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.6f ); // install the slot attribute(s) ss->getOrCreateUniform( "ocean_data", osg::Uniform::SAMPLER_2D )->set( 0 ); // set up the options uniforms. _seaLevel = new osg::Uniform(osg::Uniform::FLOAT, "ocean_seaLevel"); ss->addUniform( _seaLevel.get() ); _lowFeather = new osg::Uniform(osg::Uniform::FLOAT, "ocean_lowFeather"); ss->addUniform( _lowFeather.get() ); _highFeather = new osg::Uniform(osg::Uniform::FLOAT, "ocean_highFeather"); ss->addUniform( _highFeather.get() ); _baseColor = new osg::Uniform(osg::Uniform::FLOAT_VEC4, "ocean_baseColor"); ss->addUniform( _baseColor.get() ); _maxRange = new osg::Uniform(osg::Uniform::FLOAT, "ocean_max_range"); ss->addUniform( _maxRange.get() ); _fadeRange = new osg::Uniform(osg::Uniform::FLOAT, "ocean_fade_range"); ss->addUniform( _fadeRange.get() ); // trick to mitigate z-fighting.. ss->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0.0, 1.0, false) ); ss->setRenderingHint( osg::StateSet::TRANSPARENT_BIN ); // load up a surface texture osg::ref_ptr<osg::Image> surfaceImage; ss->getOrCreateUniform( "ocean_has_surface_tex", osg::Uniform::BOOL )->set( false ); if ( _options.textureURI().isSet() ) { //TODO: enable cache support here? surfaceImage = _options.textureURI()->getImage(); } if ( !surfaceImage.valid() ) { surfaceImage = createSurfaceImage(); } if ( surfaceImage.valid() ) { osg::Texture2D* tex = new osg::Texture2D( surfaceImage.get() ); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap ( osg::Texture::WRAP_S, osg::Texture::REPEAT ); tex->setWrap ( osg::Texture::WRAP_T, osg::Texture::REPEAT ); ss->setTextureAttributeAndModes( 2, tex, 1 ); ss->getOrCreateUniform( "ocean_surface_tex", osg::Uniform::SAMPLER_2D )->set( 2 ); ss->getOrCreateUniform( "ocean_has_surface_tex", osg::Uniform::BOOL )->set( true ); } // remove backface culling so we can see underwater // (use OVERRIDE since the terrain engine sets back face culling.) ss->setAttributeAndModes( new osg::CullFace(), osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE ); // Material. osg::Material* m = new osg::Material(); m->setAmbient(m->FRONT_AND_BACK, osg::Vec4(0,0,0,1)); m->setDiffuse(m->FRONT_AND_BACK, osg::Vec4(1,1,1,1)); m->setSpecular(m->FRONT_AND_BACK, osg::Vec4(0.1,0.1,0.1,1)); m->setEmission(m->FRONT_AND_BACK, osg::Vec4(0,0,0,1)); m->setShininess(m->FRONT_AND_BACK, 32.0); ss->setAttributeAndModes(m, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); // force apply options: applyOptions(); } }
void ClampingTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params) { // To store technique-specific per-view info: LocalPerViewData* local = new LocalPerViewData(); params._techniqueData = local; // create the projected texture: local->_rttTexture = new osg::Texture2D(); local->_rttTexture->setTextureSize( *_textureSize, *_textureSize ); local->_rttTexture->setInternalFormat( GL_DEPTH_COMPONENT ); local->_rttTexture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::NEAREST ); local->_rttTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); // this is important. geometry that is outside the depth texture will clamp to the // closest edge value in the texture -- this is good when you are rendering a // primitive that has one or more of its verts off-screen. local->_rttTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE ); local->_rttTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE ); //local->_rttTexture->setBorderColor( osg::Vec4(0,0,0,1) ); // set up the RTT camera: params._rttCamera = new osg::Camera(); params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); params._rttCamera->setClearDepth( 1.0 ); params._rttCamera->setClearMask( GL_DEPTH_BUFFER_BIT ); params._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize ); params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER ); params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); params._rttCamera->setImplicitBufferAttachmentMask(0, 0); params._rttCamera->attach( osg::Camera::DEPTH_BUFFER, local->_rttTexture.get() ); #ifdef DUMP_RTT_IMAGE local->_rttDebugImage = new osg::Image(); local->_rttDebugImage->allocateImage(4096, 4096, 1, GL_RGB, GL_UNSIGNED_BYTE); memset( (void*)local->_rttDebugImage->getDataPointer(), 0xff, local->_rttDebugImage->getTotalSizeInBytes() ); params._rttCamera->attach( osg::Camera::COLOR_BUFFER, local->_rttDebugImage.get() ); params._rttCamera->setFinalDrawCallback( new DumpTex(local->_rttDebugImage.get()) ); #endif #ifdef TIME_RTT_CAMERA params._rttCamera->setInitialDrawCallback( new RttIn() ); params._rttCamera->setFinalDrawCallback( new RttOut() ); #endif // set up a StateSet for the RTT camera. osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet(); rttStateSet->setMode( GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); // prevents wireframe mode in the depth camera. rttStateSet->setAttributeAndModes( new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL ), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); // attach the terrain to the camera. // todo: should probably protect this with a mutex..... params._rttCamera->addChild( _engine ); // the terrain itself. // assemble the overlay graph stateset. local->_groupStateSet = new osg::StateSet(); // Required for now, otherwise GPU-clamped geometry will jitter sometimes. // TODO: figure out why and fix it. This is a workaround for now. local->_groupStateSet->setDataVariance( osg::Object::DYNAMIC ); local->_groupStateSet->setTextureAttributeAndModes( _textureUnit, local->_rttTexture.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); // set up depth test/write parameters for the overlay geometry: local->_groupStateSet->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL, 0.0, 1.0, true ), osg::StateAttribute::ON ); local->_groupStateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN ); // uniform for the horizon distance (== max clamping distance) local->_horizonDistanceUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_horizonDistance", osg::Uniform::FLOAT ); // sampler for depth map texture: local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthTex", osg::Uniform::SAMPLER_2D )->set( _textureUnit ); // matrix that transforms a vert from EYE coords to the depth camera's CLIP coord. local->_camViewToDepthClipUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_cameraView2depthClip", osg::Uniform::FLOAT_MAT4 ); #ifdef SUPPORT_Z // matrix that transforms a vert from depth clip coords to depth view coords. local->_depthClipToDepthViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthClip2depthView", osg::Uniform::FLOAT_MAT4 ); // matrix that transforms a vert from depth view coords to camera view coords. local->_depthViewToCamViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthView2cameraView", osg::Uniform::FLOAT_MAT4 ); #else // matrix that transforms a vert from depth-cam CLIP coords to EYE coords. local->_depthClipToCamViewUniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_depthClip2cameraView", osg::Uniform::FLOAT_MAT4 ); #endif // make the shader that will do clamping and depth offsetting. VirtualProgram* vp = VirtualProgram::getOrCreate(local->_groupStateSet.get()); vp->setName( "ClampingTechnique" ); vp->setFunction( "oe_clamp_vertex", clampingVertexShader, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( "oe_clamp_fragment", clampingFragmentShader, ShaderComp::LOCATION_FRAGMENT_COLORING ); }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateShaders() { if ( _batchUpdateInProgress ) { _shaderUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); VirtualProgram* vp = new VirtualProgram(); vp->setName( "engine_mp:TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); // Vertex shader template: std::string vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc;\n" "varying vec4 oe_layer_tilec;\n" "void oe_mp_setup_coloring(inout vec4 VertexModel) \n" "{ \n" " oe_layer_texc = __GL_MULTITEXCOORD1__;\n" " oe_layer_tilec = __GL_MULTITEXCOORD2__;\n" "}\n"; // Fragment shader for normal blending: std::string fs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" "void oe_mp_apply_coloring( inout vec4 color ) \n" "{ \n" " vec4 texel; \n" " if ( oe_layer_uid >= 0 ) { \n" " texel = texture2D(oe_layer_tex, oe_layer_texc.st); \n" " texel.a *= oe_layer_opacity; \n" " } \n" " else \n" " texel = color; \n" " if (oe_layer_order == 0 ) \n" " color = texel*texel.a + color*(1.0-texel.a); \n" // simulate src_alpha, 1-src_alpha blens " else \n" " color = texel; \n" "} \n"; // Fragment shader with pre-multiplied alpha blending: std::string fs_pma = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" "void oe_mp_apply_coloring_pma( inout vec4 color ) \n" "{ \n" " vec4 texelpma; \n" // a UID < 0 means no texture. " if ( oe_layer_uid >= 0 ) \n" " texelpma = texture2D(oe_layer_tex, oe_layer_texc.st) * oe_layer_opacity; \n" " else \n" " texelpma = color * color.a * oe_layer_opacity; \n" // to PMA. // first layer must PMA-blend with the globe color. " if (oe_layer_order == 0) { \n" " color.rgb *= color.a; \n" " color = texelpma + color*(1.0-texelpma.a); \n" // simulate one, 1-src_alpha blend " } \n" " else { \n" " color = texelpma; \n" " } \n" "} \n"; // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "__COLOR_FILTER_HEAD__" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "__COLOR_FILTER_BODY__" "} \n"; // install the gl_MultiTexCoord* variable that uses the proper texture // image unit: replaceIn( vs, "__GL_MULTITEXCOORD1__", Stringify() << "gl_MultiTexCoord" << _primaryUnit ); replaceIn( vs, "__GL_MULTITEXCOORD2__", Stringify() << "gl_MultiTexCoord" << _secondaryUnit ); vp->setFunction( "oe_mp_setup_coloring", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); if ( _terrainOptions.premultipliedAlpha() == true ) vp->setFunction( "oe_mp_apply_coloring_pma", fs_pma, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); else vp->setFunction( "oe_mp_apply_coloring", fs, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); // assemble color filter code snippets. bool haveColorFilters = false; { std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; if ( _terrainOptions.premultipliedAlpha() == true ) { // un-PMA the color before passing it to the color filters. cf_body << I << "if (color.a > 0.0) color.rgb /= color.a; \n"; } // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( _terrainOptions.premultipliedAlpha() == true ) { // re-PMA the color after it passes through the color filters. cf_body << I << "color.rgb *= color.a; \n"; } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs_colorfilters, "__COLOR_FILTER_BODY__", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } if ( _terrainOptions.premultipliedAlpha() == true ) { // activate PMA blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); } else { // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); } // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); _shaderUpdateRequired = false; } }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth.engine_mp.TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); // Vertex shader: std::string vs = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc;\n" "varying vec4 oe_layer_tilec;\n" "void oe_mp_setup_coloring(inout vec4 VertexModel) \n" "{ \n" " oe_layer_texc = gl_MultiTexCoord" << _primaryUnit << ";\n" " oe_layer_tilec = gl_MultiTexCoord" << _secondaryUnit << ";\n" "}\n"; bool useTerrainColor = _terrainOptions.color().isSet(); bool useBlending = _terrainOptions.enableBlending() == true; // Fragment Shader for normal blending: std::string fs = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" << (useTerrainColor ? "uniform vec4 oe_terrain_color; \n" : "" ) << "void oe_mp_apply_coloring(inout vec4 color) \n" "{ \n" << (useTerrainColor ? " color = oe_terrain_color; \n" : "" ) << //" color = vec4(1,1,1,1); \n" " vec4 texel; \n" " if ( oe_layer_uid >= 0 ) { \n" " texel = texture2D(oe_layer_tex, oe_layer_texc.st); \n" " texel.a *= oe_layer_opacity; \n" " } \n" " else \n" " texel = color; \n" " " << (useBlending ? " if ( oe_layer_order == 0 ) \n" " color = texel*texel.a + color*(1.0-texel.a); \n" // simulate src_alpha, 1-src_alpha blens " else \n" : "" ) << " color = texel; \n" "} \n"; // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "__COLOR_FILTER_HEAD__" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "__COLOR_FILTER_BODY__" "} \n"; vp->setFunction( "oe_mp_setup_coloring", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); vp->setFunction( "oe_mp_apply_coloring", fs, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); // assemble color filter code snippets. bool haveColorFilters = false; { std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs_colorfilters, "__COLOR_FILTER_BODY__", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // binding for the default secondary texture matrix osg::Matrixf parent_mat; parent_mat(0,0) = 0.0f; terrainStateSet->getOrCreateUniform( "oe_layer_parent_matrix", osg::Uniform::FLOAT_MAT4 )->set( parent_mat ); // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); // base terrain color. if ( useTerrainColor ) { terrainStateSet->getOrCreateUniform( "oe_terrain_color", osg::Uniform::FLOAT_VEC4 )->set( *_terrainOptions.color() ); } } _stateUpdateRequired = false; } }
void PolygonizeLinesOperator::installShaders(osg::Node* node) const { if ( !node ) return; float minPixels = _stroke.minPixels().getOrUse( 0.0f ); if ( minPixels <= 0.0f ) return; osg::StateSet* stateset = node->getOrCreateStateSet(); VirtualProgram* vp = VirtualProgram::getOrCreate(stateset); // bail if already installed. if ( vp->getName().compare( SHADER_NAME ) == 0 ) return; vp->setName( SHADER_NAME ); const char* vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "in vec3 oe_polyline_center; \n" "uniform float oe_polyline_scale; \n" "uniform float oe_polyline_min_pixels; \n" "uniform vec4 oe_PixelSizeVector; \n" "void oe_polyline_scalelines(inout vec4 vertex_model4) \n" "{ \n" " const float epsilon = 0.0001; \n" " vec4 center = vec4(oe_polyline_center, 1.0); \n" " vec3 vector = vertex_model4.xyz - center.xyz; \n" " float r = length(vector); \n" " float activate = step(epsilon, r*oe_polyline_min_pixels);\n" " float pixelSize = max(epsilon, 2.0*abs(r/dot(center, oe_PixelSizeVector))); \n" " float min_scale = max(oe_polyline_min_pixels/pixelSize, 1.0); \n" " float scale = mix(1.0, max(oe_polyline_scale, min_scale), activate); \n" " vertex_model4.xyz = center.xyz + vector*scale; \n" "} \n"; vp->setFunction( "oe_polyline_scalelines", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.5f ); vp->addBindAttribLocation( "oe_polyline_center", ATTR_LOCATION ); // add the default scaling uniform. // good way to test: // osgearth_viewer earthfile --uniform oe_polyline_scale 1.0 10.0 osg::Uniform* scaleU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_scale"); scaleU->set( 1.0f ); stateset->addUniform( scaleU, 1 ); // the default "min pixels" uniform. osg::Uniform* minPixelsU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_min_pixels"); minPixelsU->set( minPixels ); stateset->addUniform( minPixelsU, 1 ); // this will install and update the oe_PixelSizeVector uniform. node->addCullCallback( new PixelSizeVectorCullCallback(stateset) ); }
void SimpleOceanNode::rebuild() { this->removeChildren( 0, this->getNumChildren() ); osg::ref_ptr<MapNode> mapNode; if (_parentMapNode.lock(mapNode)) { const MapOptions& parentMapOptions = mapNode->getMap()->getMapOptions(); const MapNodeOptions& parentMapNodeOptions = mapNode->getMapNodeOptions(); // set up the map to "match" the parent map: MapOptions mo; mo.coordSysType() = parentMapOptions.coordSysType(); mo.profile() = mapNode->getMap()->getProfile()->toProfileOptions(); // new data model for the ocean: Map* oceanMap = new Map( mo ); // ditto with the map node options: MapNodeOptions mno; if ( mno.enableLighting().isSet() ) mno.enableLighting() = *mno.enableLighting(); RexTerrainEngineOptions terrainoptions; terrainoptions.enableBlending() = true; // gotsta blend with the main node terrainoptions.color() = baseColor().get(); terrainoptions.tileSize() = 5; mno.setTerrainOptions( terrainoptions ); // make the ocean's map node: MapNode* oceanMapNode = new MapNode( oceanMap, mno ); // set up the shaders. osg::StateSet* ss = this->getOrCreateStateSet(); // if the caller requested a mask layer, install that now. if ( maskLayer().isSet() ) { if ( !maskLayer()->maxLevel().isSet() ) { // set the max subdivision level if it's not already specified in the // mask layer options: maskLayer()->maxLevel() = maxLOD().get(); } // make sure the mask is shared (so we can access it from our shader) // and invisible (so we can't see it) maskLayer()->shared() = true; maskLayer()->visible() = false; ImageLayer* layer = new ImageLayer("ocean-mask", maskLayer().get()); oceanMap->addLayer( layer ); ss->setDefine("OE_SIMPLE_OCEAN_USE_MASK"); OE_INFO << LC << "Using mask layer \"" << layer->getName() << "\"\n"; } // otherwise, install a "proxy layer" that will use the elevation data in the map // to determine where the ocean is. This approach is limited in that it cannot // detect the difference between ocean and inland areas that are below sea level. else { // install an "elevation proxy" layer that reads elevation tiles from the // parent map and turns them into encoded images for our shader to use. ImageLayerOptions epo( "ocean-proxy" ); epo.cachePolicy() = CachePolicy::NO_CACHE; epo.shared() = true; epo.visible() = false; epo.shareTexUniformName() = "oe_ocean_proxyTex"; epo.shareTexMatUniformName() = "oe_ocean_proxyMat"; oceanMap->addLayer( new ElevationProxyImageLayer(mapNode->getMap(), epo) ); OE_INFO << LC << "Using elevation proxy layer\n"; } this->addChild( oceanMapNode ); // install the shaders on the ocean map node. VirtualProgram* vp = VirtualProgram::getOrCreate( ss ); vp->setName( "osgEarth SimpleOcean" ); Shaders shaders; shaders.loadAll(vp, 0L); // set up the options uniforms. _seaLevel = new osg::Uniform(osg::Uniform::FLOAT, "ocean_seaLevel"); ss->addUniform( _seaLevel.get() ); _lowFeather = new osg::Uniform(osg::Uniform::FLOAT, "ocean_lowFeather"); ss->addUniform( _lowFeather.get() ); _highFeather = new osg::Uniform(osg::Uniform::FLOAT, "ocean_highFeather"); ss->addUniform( _highFeather.get() ); _baseColor = new osg::Uniform(osg::Uniform::FLOAT_VEC4, "ocean_baseColor"); ss->addUniform( _baseColor.get() ); _maxRange = new osg::Uniform(osg::Uniform::FLOAT, "ocean_max_range"); ss->addUniform( _maxRange.get() ); _fadeRange = new osg::Uniform(osg::Uniform::FLOAT, "ocean_fade_range"); ss->addUniform( _fadeRange.get() ); _alphaUniform = new osg::Uniform(osg::Uniform::FLOAT, "oe_ocean_alpha"); ss->addUniform( _alphaUniform.get() ); // disable depth writes. ss->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0.0, 1.0, false) ); // load up a surface texture osg::ref_ptr<osg::Image> surfaceImage; if ( textureURI().isSet() ) { surfaceImage = textureURI()->getImage(); } //if ( !surfaceImage.valid() ) //{ // surfaceImage = createSurfaceImage(); //} if ( surfaceImage.valid() ) { osg::Texture2D* tex = new osg::Texture2D( surfaceImage.get() ); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap ( osg::Texture::WRAP_S, osg::Texture::REPEAT ); tex->setWrap ( osg::Texture::WRAP_T, osg::Texture::REPEAT ); ss->setTextureAttributeAndModes( 5, tex, 1 ); ss->getOrCreateUniform( "ocean_surface_tex", osg::Uniform::SAMPLER_2D )->set( 5 ); ss->setDefine("OE_SIMPLE_OCEAN_USE_TEXTURE"); OE_INFO << LC << "Using a surface texture (" << surfaceImage->getFileName() << ")\n"; } // remove backface culling so we can see underwater // (use OVERRIDE since the terrain engine sets back face culling.) ss->setAttributeAndModes( new osg::CullFace(), osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE ); // Material. osg::Material* m = new osgEarth::MaterialGL3(); m->setAmbient(m->FRONT_AND_BACK, osg::Vec4(.5,.5,.5,1)); m->setDiffuse(m->FRONT_AND_BACK, osg::Vec4(1,1,1,1)); m->setSpecular(m->FRONT_AND_BACK, osg::Vec4(0.2,0.2,0.2,1)); m->setEmission(m->FRONT_AND_BACK, osg::Vec4(0,0,0,1)); m->setShininess(m->FRONT_AND_BACK, 40.0); ss->setAttributeAndModes(m, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); // force apply options: applyOptions(); } }
void DrapingTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params) { // 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_BORDER ); projTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER ); //projTexture->setWrap( osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE ); projTexture->setBorderColor( osg::Vec4(0,0,0,0) ); // set up the RTT camera: params._rttCamera = new osg::Camera(); params._rttCamera->setClearColor( osg::Vec4f(0,0,0,0) ); // 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) params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ); params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize ); params._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER ); params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT ); params._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::capabilities().supportsDepthPackedStencilBuffer() ) { #ifdef OSG_GLES2_AVAILABLE params._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH24_STENCIL8_EXT ); #else params._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH_STENCIL_EXT ); #endif } else { params._rttCamera->attach( osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX ); } params._rttCamera->setClearStencil( 0 ); params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); } else { params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } // set up a StateSet for the RTT camera. osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet(); // lighting is off. We don't want draped items to be lit. 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 = VirtualProgram::getOrCreate(rttStateSet); vp->setName( "DrapingTechnique RTT" ); vp->setInheritShaders( false ); //rttStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // active blending within the RTT camera's FBO 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::capabilities().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 group to the camera. // TODO: we should probably lock this since other cull traversals might be accessing the group // while we are changing its children. params._rttCamera->addChild( params._group ); // 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" ); // add to the terrain stateset, i.e. the stateset that the OverlayDecorator will // apply to the terrain before cull-traversing it. This will activate the projective // texturing on the terrain. params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, projTexture, osg::StateAttribute::ON ); // fire up the local per-view data: LocalPerViewData* local = new LocalPerViewData(); params._techniqueData = local; if ( _useShaders ) { // GPU path VirtualProgram* vp = VirtualProgram::getOrCreate(params._terrainStateSet); vp->setName( "DrapingTechnique terrain shaders"); //params._terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // sampler for projected texture: params._terrainStateSet->getOrCreateUniform( "oe_overlay_tex", osg::Uniform::SAMPLER_2D )->set( *_textureUnit ); // the texture projection matrix uniform. local->_texGenUniform = params._terrainStateSet->getOrCreateUniform( "oe_overlay_texmatrix", osg::Uniform::FLOAT_MAT4 ); // vertex shader - subgraph std::string vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform mat4 oe_overlay_texmatrix; \n" "varying vec4 oe_overlay_texcoord; \n" "void oe_overlay_vertex(inout vec4 VertexVIEW) \n" "{ \n" " oe_overlay_texcoord = oe_overlay_texmatrix * VertexVIEW; \n" "} \n"; vp->setFunction( "oe_overlay_vertex", vs, ShaderComp::LOCATION_VERTEX_VIEW ); // fragment shader - subgraph std::string fs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform sampler2D oe_overlay_tex; \n" "varying vec4 oe_overlay_texcoord; \n" "void oe_overlay_fragment( inout vec4 color ) \n" "{ \n" " vec4 texel = texture2DProj(oe_overlay_tex, oe_overlay_texcoord); \n" " color = vec4( mix( color.rgb, texel.rgb, texel.a ), color.a); \n" "} \n"; vp->setFunction( "oe_overlay_fragment", fs, ShaderComp::LOCATION_FRAGMENT_COLORING ); } else { // FFP path local->_texGen = new osg::TexGen(); local->_texGen->setMode( osg::TexGen::EYE_LINEAR ); params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, local->_texGen.get(), 1 ); osg::TexEnv* env = new osg::TexEnv(); env->setMode( osg::TexEnv::DECAL ); params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, env, 1 ); } }
// Generates the main shader code for rendering the terrain. void RexTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // everything osg::StateSet* surfaceStateSet = getSurfaceStateSet(); // just the surface //terrainStateSet->setRenderBinDetails(0, "SORT_FRONT_TO_BACK"); // required for multipass tile rendering to work surfaceStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); surfaceStateSet->setAttributeAndModes( new osg::CullFace(), osg::StateAttribute::ON); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install patch param if we are tessellation on the GPU. if ( _terrainOptions.gpuTessellation() == true ) { #ifdef HAVE_PATCH_PARAMETER terrainStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { Shaders package; VirtualProgram* terrainVP = VirtualProgram::getOrCreate(terrainStateSet); terrainVP->setName( "Rex Terrain" ); package.load(terrainVP, package.ENGINE_VERT_MODEL); surfaceStateSet->addUniform(new osg::Uniform("oe_terrain_color", _terrainOptions.color().get())); if (_terrainOptions.enableBlending() == true) { surfaceStateSet->setDefine("OE_TERRAIN_BLEND_IMAGERY"); } // Funtions that affect only the terrain surface: VirtualProgram* surfaceVP = VirtualProgram::getOrCreate(surfaceStateSet); surfaceVP->setName("Rex Surface"); // Functions that affect the terrain surface only: package.load(surfaceVP, package.ENGINE_VERT_VIEW); package.load(surfaceVP, package.ENGINE_FRAG); // Elevation? if (this->elevationTexturesRequired()) { surfaceStateSet->setDefine("OE_TERRAIN_RENDER_ELEVATION"); } // Normal mapping shaders: if ( this->normalTexturesRequired() ) { package.load(surfaceVP, package.NORMAL_MAP_VERT); package.load(surfaceVP, package.NORMAL_MAP_FRAG); surfaceStateSet->setDefine("OE_TERRAIN_RENDER_NORMAL_MAP"); } // Morphing? if (_terrainOptions.morphTerrain() == true || _terrainOptions.morphImagery() == true) { package.load(surfaceVP, package.MORPHING_VERT); if (_terrainOptions.morphImagery() == true) { surfaceStateSet->setDefine("OE_TERRAIN_MORPH_IMAGERY"); } if (_terrainOptions.morphTerrain() == true) { surfaceStateSet->setDefine("OE_TERRAIN_MORPH_GEOMETRY"); } } // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_rexEngine_applyFilters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; ImageLayerVector imageLayers; _update_mapf->getLayers(imageLayers); for( int i=0; i<imageLayers.size(); ++i ) { ImageLayer* layer = imageLayers.at(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( surfaceStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); surfaceVP->setFunction( "oe_rexEngine_applyFilters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.6 ); } } // Apply uniforms for sampler bindings: OE_DEBUG << LC << "Render Bindings:\n"; osg::ref_ptr<osg::Texture> tex = new osg::Texture2D(ImageUtils::createEmptyImage(1,1)); for (unsigned i = 0; i < _renderBindings.size(); ++i) { SamplerBinding& b = _renderBindings[i]; if (b.isActive()) { osg::Uniform* u = new osg::Uniform(b.samplerName().c_str(), b.unit()); terrainStateSet->addUniform( u ); OE_DEBUG << LC << " > Bound \"" << b.samplerName() << "\" to unit " << b.unit() << "\n"; terrainStateSet->setTextureAttribute(b.unit(), tex.get()); } } // uniform that controls per-layer opacity terrainStateSet->addUniform( new osg::Uniform("oe_layer_opacity", 1.0f) ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->addUniform( new osg::Uniform("oe_layer_uid", (int)-1 ) ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->addUniform( new osg::Uniform("oe_layer_order", (int)0) ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_attenuationRange", _terrainOptions.attentuationDistance().get()) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); terrainStateSet->addUniform(new osg::Uniform("oe_tile_size", (float)_terrainOptions.tileSize().get())); // special object ID that denotes the terrain surface. surfaceStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
osg::StateSet* Text::createStateSet() { #if OSG_VERSION_GREATER_OR_EQUAL(3,5,8) // NOTE: Most of this is copied from the parent class, except for the // added osgEarth defines and the VirtualProgram in place of the Program. osgText::Font* activeFont = getActiveFont(); if (!activeFont) return 0; osgText::Font::StateSets& statesets = activeFont->getCachedStateSets(); std::stringstream ss; ss<<std::fixed<<std::setprecision(3); osg::StateSet::DefineList defineList; if (_backdropType!=NONE) { ss.str(""); ss << "vec4("<<_backdropColor.r()<<", "<<_backdropColor.g()<<", "<<_backdropColor.b()<<", "<<_backdropColor.a()<<")"; defineList["BACKDROP_COLOR"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON); if (_backdropType==OUTLINE) { ss.str(""); ss <<_backdropHorizontalOffset; defineList["OUTLINE"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON); } else { osg::Vec2 offset(_backdropHorizontalOffset, _backdropVerticalOffset); switch(_backdropType) { case(DROP_SHADOW_BOTTOM_RIGHT) : offset.set(_backdropHorizontalOffset, -_backdropVerticalOffset); break; case(DROP_SHADOW_CENTER_RIGHT) : offset.set(_backdropHorizontalOffset, 0.0f); break; case(DROP_SHADOW_TOP_RIGHT) : offset.set(_backdropHorizontalOffset, _backdropVerticalOffset); break; case(DROP_SHADOW_BOTTOM_CENTER) : offset.set(0.0f, -_backdropVerticalOffset); break; case(DROP_SHADOW_TOP_CENTER) : offset.set(0.0f, _backdropVerticalOffset); break; case(DROP_SHADOW_BOTTOM_LEFT) : offset.set(-_backdropHorizontalOffset, -_backdropVerticalOffset); break; case(DROP_SHADOW_CENTER_LEFT) : offset.set(-_backdropHorizontalOffset, 0.0f); break; case(DROP_SHADOW_TOP_LEFT) : offset.set(-_backdropHorizontalOffset, _backdropVerticalOffset); break; default : break; } ss.str(""); ss << "vec2("<<offset.x()<<", "<<offset.y()<<")"; defineList["SHADOW"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON); } } { ss<<std::fixed<<std::setprecision(1); ss.str(""); ss << float(_fontSize.second); defineList["GLYPH_DIMENSION"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON); ss.str(""); ss << float(activeFont->getTextureWidthHint()); defineList["TEXTURE_DIMENSION"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON); } if (_shaderTechnique>osgText::GREYSCALE) { defineList["SIGNED_DISTANCE_FIELD"] = osg::StateSet::DefinePair("1", osg::StateAttribute::ON); } #if 0 OSG_NOTICE<<"Text::createStateSet() defines:"<<defineList.size()<<std::endl; for(osg::StateSet::DefineList::iterator itr = defineList.begin(); itr != defineList.end(); ++itr) { OSG_NOTICE<<" define["<<itr->first<<"] = "<<itr->second.first<<std::endl; } #endif // osgEarth:: add defines #if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE) defineList["OSGTEXT_GLYPH_ALPHA_FORMAT_IS_RED"] = osg::StateSet::DefinePair("1", osg::StateAttribute::ON); #endif defineList[OE_LIGHTING_DEFINE] = osg::StateSet::DefinePair("", osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED); // The remaining of this method is exclusive so we don't corrupt the // stateset cache when creating text objects from multiple threads. -gw static Threading::Mutex mutex; Threading::ScopedMutexLock lock(mutex); if (!statesets.empty()) { for(osgText::Font::StateSets::iterator itr = statesets.begin(); itr != statesets.end(); ++itr) { if ((*itr)->getDefineList()==defineList) { // OSG_NOTICE<<"Text::createStateSet() : Matched DefineList, return StateSet "<<itr->get()<<std::endl; return itr->get(); } else { } } } osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet; stateset->setDefineList(defineList); statesets.push_back(stateset.get()); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateset->setMode(GL_BLEND, osg::StateAttribute::ON); #if defined(OSG_GL_FIXED_FUNCTION_AVAILABLE) osg::DisplaySettings::ShaderHint shaderHint = osg::DisplaySettings::instance()->getShaderHint(); if (_shaderTechnique==osgText::NO_TEXT_SHADER && shaderHint==osg::DisplaySettings::SHADER_NONE) { stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); return stateset.release(); } #endif // set up the StateSet to use shaders stateset->addUniform(new osg::Uniform("glyphTexture", 0)); // osgEarth: add shaders VirtualProgram* vp = VirtualProgram::getOrCreate(stateset.get()); vp->setName("osgEarth::Text"); osgEarth::Shaders coreShaders; coreShaders.load(vp, coreShaders.TextVertex); coreShaders.load(vp, coreShaders.TextFragment); return stateset.release(); #else return 0L; #endif }
osg::Node* PolygonizeLinesFilter::push(FeatureList& input, FilterContext& cx) { // compute the coordinate localization matrices. computeLocalizers( cx ); // establish some things bool makeECEF = false; const SpatialReference* featureSRS = 0L; const SpatialReference* mapSRS = 0L; if ( cx.isGeoreferenced() ) { makeECEF = cx.getSession()->getMapInfo().isGeocentric(); featureSRS = cx.extent()->getSRS(); mapSRS = cx.getSession()->getMapInfo().getProfile()->getSRS(); } // The operator we'll use to make lines into polygons. const LineSymbol* line = _style.get<LineSymbol>(); PolygonizeLinesOperator polygonize( line ? (*line->stroke()) : Stroke() ); // Geode to hold all the geometries. osg::Geode* geode = new osg::Geode(); // iterate over all features. for( FeatureList::iterator i = input.begin(); i != input.end(); ++i ) { Feature* f = i->get(); // iterate over all the feature's geometry parts. We will treat // them as lines strings. GeometryIterator parts( f->getGeometry(), false ); while( parts.hasMore() ) { Geometry* part = parts.next(); // skip empty geometry if ( part->size() == 0 ) continue; // transform the geometry into the target SRS and localize it about // a local reference point. osg::Vec3Array* verts = new osg::Vec3Array(); osg::Vec3Array* normals = new osg::Vec3Array(); transformAndLocalize( part->asVector(), featureSRS, verts, normals, mapSRS, _world2local, makeECEF ); // turn the lines into polygons. osg::Geometry* geom = polygonize( verts, normals ); geode->addDrawable( geom ); // record the geometry's primitive set(s) in the index: if ( cx.featureIndex() ) cx.featureIndex()->tagPrimitiveSets( geom, f ); } } // attempt to combine geometries for better performance MeshConsolidator::run( *geode ); // GPU performance optimization: VertexCacheOptimizer vco; geode->accept( vco ); // If we're auto-scaling, we need a shader float minPixels = line ? line->stroke()->minPixels().getOrUse( 0.0f ) : 0.0f; if ( minPixels > 0.0f ) { osg::StateSet* stateSet = geode->getOrCreateStateSet(); VirtualProgram* vp = VirtualProgram::getOrCreate(stateSet); vp->setName( "osgEarth::PolygonizeLines" ); const char* vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "attribute vec3 oe_polyline_center; \n" "uniform float oe_polyline_scale; \n" "uniform float oe_polyline_min_pixels; \n" "uniform mat3 oe_WindowScaleMatrix; \n" "void oe_polyline_scalelines(inout vec4 VertexMODEL) \n" "{ \n" " if ( oe_polyline_scale != 1.0 || oe_polyline_min_pixels > 0.0 ) \n" " { \n" " vec4 center_model = vec4(oe_polyline_center*VertexMODEL.w, VertexMODEL.w); \n" " vec4 vector_model = VertexMODEL - center_model; \n" " if ( length(vector_model.xyz) > 0.0 ) \n" " { \n" " float scale = oe_polyline_scale; \n" " vec4 vertex_clip = gl_ModelViewProjectionMatrix * VertexMODEL; \n" " vec4 center_clip = gl_ModelViewProjectionMatrix * center_model; \n" " vec4 vector_clip = vertex_clip - center_clip; \n" " if ( oe_polyline_min_pixels > 0.0 ) \n" " { \n" " vec3 vector_win = oe_WindowScaleMatrix * (vertex_clip.xyz/vertex_clip.w - center_clip.xyz/center_clip.w); \n" " float min_scale = max( (0.5*oe_polyline_min_pixels)/length(vector_win.xy), 1.0 ); \n" " scale = max( scale, min_scale ); \n" " } \n" " VertexMODEL = center_model + vector_model*scale; \n" " } \n" " } \n" "} \n"; vp->setFunction( "oe_polyline_scalelines", vs, ShaderComp::LOCATION_VERTEX_MODEL ); vp->addBindAttribLocation( "oe_polyline_center", osg::Drawable::ATTRIBUTE_6 ); // add the default scaling uniform. // good way to test: // osgearth_viewer earthfile --uniform oe_polyline_scale 1.0 10.0 osg::Uniform* scaleU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_scale"); scaleU->set( 1.0f ); stateSet->addUniform( scaleU, 1 ); // the default "min pixels" uniform. osg::Uniform* minPixelsU = new osg::Uniform(osg::Uniform::FLOAT, "oe_polyline_min_pixels"); minPixelsU->set( minPixels ); stateSet->addUniform( minPixelsU, 1 ); } return delocalize( geode ); }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { if ( _elevationTextureUnit < 0 && elevationTexturesRequired() ) { getResources()->reserveTextureImageUnit( _elevationTextureUnit, "MP Engine Elevation" ); } osg::StateSet* terrainStateSet = getTerrainStateSet(); // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth.engine_mp.TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); Shaders package; package.replace( "$MP_PRIMARY_UNIT", Stringify() << _primaryUnit ); package.replace( "$MP_SECONDARY_UNIT", Stringify() << (_secondaryUnit>=0?_secondaryUnit:0) ); package.define( "MP_USE_BLENDING", (_terrainOptions.enableBlending() == true) ); package.loadFunction( vp, package.VertexModel ); package.loadFunction( vp, package.VertexView ); package.loadFunction( vp, package.Fragment ); // terrain background color; negative means use the vertex color. Color terrainColor = _terrainOptions.color().getOrUse( Color(1,1,1,-1) ); terrainStateSet->addUniform(new osg::Uniform("oe_terrain_color", terrainColor)); // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.5f ); } } // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) if ( parentTexturesRequired() ) { terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // binding for the default secondary texture matrix osg::Matrixf parent_mat; parent_mat(0,0) = 0.0f; terrainStateSet->getOrCreateUniform( "oe_layer_parent_matrix", osg::Uniform::FLOAT_MAT4 )->set( parent_mat ); } // uniform for accessing the elevation texture sampler. if ( elevationTexturesRequired() ) { terrainStateSet->getOrCreateUniform( "oe_terrain_tex", osg::Uniform::SAMPLER_2D)->set( _elevationTextureUnit ); } // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); // special object ID that denotes the terrain surface. terrainStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
void OverlayDecorator::initSubgraphShaders( osg::StateSet* set ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "OverlayDecorator subgraph shader" ); set->setAttributeAndModes( vp, osg::StateAttribute::ON ); // sampler for projected texture: set->getOrCreateUniform( "osgearth_overlay_ProjTex", osg::Uniform::SAMPLER_2D )->set( *_textureUnit ); // the texture projection matrix uniform. _texGenUniform = set->getOrCreateUniform( "osgearth_overlay_TexGenMatrix", osg::Uniform::FLOAT_MAT4 ); std::stringstream buf; // vertex shader - subgraph buf << "#version 110 \n" << "uniform mat4 osgearth_overlay_TexGenMatrix; \n" << "uniform mat4 osg_ViewMatrixInverse; \n" << "void osgearth_overlay_vertex(void) \n" << "{ \n" << " gl_TexCoord["<< *_textureUnit << "] = osgearth_overlay_TexGenMatrix * osg_ViewMatrixInverse * gl_ModelViewMatrix * gl_Vertex; \n" << "} \n"; std::string vertexSource = buf.str(); vp->setFunction( "osgearth_overlay_vertex", vertexSource, ShaderComp::LOCATION_VERTEX_POST_LIGHTING ); // fragment shader - subgraph buf.str(""); buf << "#version 110 \n" << "uniform sampler2D osgearth_overlay_ProjTex; \n"; if ( _useWarping ) { buf << "uniform float warp; \n" // because the built-in pow() is busted << "float mypow( in float x, in float y ) \n" << "{ \n" << " return x/(x+y-y*x); \n" << "} \n" << "vec2 warpTexCoord( in vec2 src ) \n" << "{ \n" // incoming tex coord is [0..1], so we scale to [-1..1] << " vec2 srcn = vec2( src.x*2.0 - 1.0, src.y*2.0 - 1.0 ); \n" // we want to work in the [0..1] space on each side of 0, so can the abs // and store the signs for later: << " vec2 srct = vec2( abs(srcn.x), abs(srcn.y) ); \n" << " vec2 sign = vec2( srcn.x > 0.0 ? 1.0 : -1.0, srcn.y > 0.0 ? 1.0 : -1.0 ); \n" // apply the deformation using a deceleration curve: << " vec2 srcp = vec2( 1.0-mypow(1.0-srct.x,warp), 1.0-mypow(1.0-srct.y,warp) ); \n" // reapply the sign, and scale back to [0..1]: << " vec2 srcr = vec2( sign.x*srcp.x, sign.y*srcp.y ); \n" << " return vec2( 0.5*(srcr.x + 1.0), 0.5*(srcr.y + 1.0) ); \n" << "} \n"; } buf << "void osgearth_overlay_fragment( inout vec4 color ) \n" << "{ \n" << " vec2 texCoord = gl_TexCoord["<< *_textureUnit << "].xy / gl_TexCoord["<< *_textureUnit << "].q; \n"; if ( _useWarping && !_visualizeWarp ) buf << " texCoord = warpTexCoord( texCoord ); \n"; buf << " vec4 texel = texture2D(osgearth_overlay_ProjTex, texCoord); \n" << " color = vec4( mix( color.rgb, texel.rgb, texel.a ), color.a); \n" << "} \n"; std::string fragmentSource = buf.str(); vp->setFunction( "osgearth_overlay_fragment", fragmentSource, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); }
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(); }
bool BillboardExtension::connect(MapNode* mapNode) { if ( !mapNode ) { OE_WARN << LC << "Illegal: MapNode cannot be null." << std::endl; return false; } OE_INFO << LC << "Connecting to MapNode.\n"; if ( !_options.imageURI().isSet() ) { OE_WARN << LC << "Illegal: image URI is required" << std::endl; return false; } if ( !_options.featureOptions().isSet() ) { OE_WARN << LC << "Illegal: feature source is required" << std::endl; return false; } _features = FeatureSourceFactory::create( _options.featureOptions().value() ); if ( !_features.valid() ) { OE_WARN << LC << "Illegal: no valid feature source provided" << std::endl; return false; } //if ( _features->getGeometryType() != osgEarth::Symbology::Geometry::TYPE_POINTSET ) //{ // OE_WARN << LC << "Illegal: only points currently supported" << std::endl; // return false; //} _features->initialize( _dbOptions ); osg::Vec3dArray* verts; if ( _features->getFeatureProfile() ) { verts = new osg::Vec3dArray(); OE_NOTICE << "Reading features...\n"; osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor(); while ( cursor.valid() && cursor->hasMore() ) { Feature* f = cursor->nextFeature(); if ( f && f->getGeometry() ) { if ( f->getGeometry()->getComponentType() == Geometry::TYPE_POLYGON ) { FilterContext cx; cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) ); ScatterFilter scatter; scatter.setDensity( _options.density().get() ); scatter.setRandom( true ); FeatureList featureList; featureList.push_back(f); scatter.push( featureList, cx ); } // Init a filter to tranform feature in desired SRS if (!mapNode->getMapSRS()->isEquivalentTo(_features->getFeatureProfile()->getSRS())) { FilterContext cx; cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) ); TransformFilter xform( mapNode->getMapSRS() ); FeatureList featureList; featureList.push_back(f); cx = xform.push(featureList, cx); } GeometryIterator iter(f->getGeometry()); while(iter.hasMore()) { const Geometry* geom = iter.next(); osg::ref_ptr<osg::Vec3dArray> fVerts = geom->createVec3dArray(); verts->insert(verts->end(), fVerts->begin(), fVerts->end()); } } } } else { OE_WARN << LC << "Illegal: feature source has no SRS" << std::endl; return false; } if ( verts && verts->size() > 0 ) { OE_NOTICE << LC << "Read " << verts->size() << " points.\n"; //localize all the verts GeoPoint centroid; _features->getFeatureProfile()->getExtent().getCentroid(centroid); centroid = centroid.transform(mapNode->getMapSRS()); OE_NOTICE << "Centroid = " << centroid.x() << ", " << centroid.y() << "\n"; osg::Matrixd l2w, w2l; centroid.createLocalToWorld(l2w); w2l.invert(l2w); osg::MatrixTransform* mt = new osg::MatrixTransform; mt->setMatrix(l2w); OE_NOTICE << "Clamping elevations...\n"; osgEarth::ElevationQuery eq(mapNode->getMap()); eq.setFallBackOnNoData( true ); eq.getElevations(verts->asVector(), mapNode->getMapSRS(), true, 0.005); OE_NOTICE << "Building geometry...\n"; osg::Vec3Array* normals = new osg::Vec3Array(verts->size()); osg::Vec4Array* colors = new osg::Vec4Array(verts->size()); Random rng; for (int i=0; i < verts->size(); i++) { GeoPoint vert(mapNode->getMapSRS(), (*verts)[i], osgEarth::ALTMODE_ABSOLUTE); osg::Vec3d world; vert.toWorld(world); (*verts)[i] = world * w2l; osg::Vec3 normal = world; normal.normalize(); (*normals)[i] = osg::Matrix::transform3x3(normal, w2l); double n = rng.next(); (*colors)[i].set( n, n, n, 1 ); } //create geom and primitive sets osg::Geometry* geometry = new osg::Geometry(); geometry->setVertexArray( verts ); geometry->setNormalArray( normals ); geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX ); geometry->setColorArray(colors); geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); geometry->addPrimitiveSet( new osg::DrawArrays( GL_POINTS, 0, verts->size() ) ); //create image and texture to render to osg::Texture2D* tex = new osg::Texture2D(_options.imageURI()->getImage(_dbOptions)); tex->setResizeNonPowerOfTwoHint(false); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); geometry->setName("BillboardPoints"); osg::Geode* geode = new osg::Geode; geode->addDrawable(geometry); //osg::ref_ptr<StateSetCache> cache = new StateSetCache(); //Registry::shaderGenerator().run(geode, cache.get()); //set the texture related uniforms osg::StateSet* geode_ss = geode->getOrCreateStateSet(); geode_ss->setTextureAttributeAndModes( 2, tex, 1 ); geode_ss->getOrCreateUniform("billboard_tex", osg::Uniform::SAMPLER_2D)->set( 2 ); float bbWidth = (float)tex->getImage()->s() / 2.0f; float bbHeight = (float)tex->getImage()->t(); float aspect = (float)tex->getImage()->s() / (float)tex->getImage()->t(); if (_options.height().isSet()) { bbHeight = _options.height().get(); if (!_options.width().isSet()) { bbWidth = bbHeight * aspect / 2.0f; } } if (_options.width().isSet()) { bbWidth = _options.width().get() / 2.0f; if (!_options.height().isSet()) { bbHeight = _options.width().get() / aspect; } } geode_ss->getOrCreateUniform("billboard_width", osg::Uniform::FLOAT)->set( bbWidth ); geode_ss->getOrCreateUniform("billboard_height", osg::Uniform::FLOAT)->set( bbHeight ); geode_ss->setMode(GL_BLEND, osg::StateAttribute::ON); //for now just using an osg::Program //TODO: need to add GeometryShader support to the shader comp setup VirtualProgram* vp = VirtualProgram::getOrCreate(geode_ss); vp->setName( "osgEarth Billboard Extension" ); ShaderPackage shaders; shaders.add( "Billboard geometry shader", billboardGeomShader ); shaders.add( "Billboard fragment shader", billboardFragShader ); shaders.loadAll( vp ); geode_ss->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); geode->setCullingActive(false); mt->addChild(geode); mapNode->getModelLayerGroup()->addChild(mt); return true; } return false; }