osg::Shader* ShaderFactory::createColorFilterChainFragmentShader( const std::string& function, const ColorFilterChain& chain ) const { std::stringstream buf; buf << "#version " << GLSL_VERSION_STR << "\n" << PRECISION_MEDIUMP_FLOAT << "\n"; // write out the shader function prototypes: for( ColorFilterChain::const_iterator i = chain.begin(); i != chain.end(); ++i ) { ColorFilter* filter = i->get(); buf << "void " << filter->getEntryPointFunctionName() << "(in int slot, inout vec4 color);\n"; } // write out the main function: buf << "void " << function << "(in int slot, inout vec4 color) \n" << "{ \n"; // write out the function calls. if there are none, it's a NOP. for( ColorFilterChain::const_iterator i = chain.begin(); i != chain.end(); ++i ) { ColorFilter* filter = i->get(); buf << " " << filter->getEntryPointFunctionName() << "(slot, color);\n"; } buf << "} \n"; std::string bufstr; bufstr = buf.str(); return new osg::Shader(osg::Shader::FRAGMENT, bufstr); }
void QuadTreeTerrainEngineNode::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(); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); #if 0 VirtualProgram* vp = dynamic_cast<VirtualProgram*>( terrainStateSet->getAttribute(osg::StateAttribute::PROGRAM) ); if ( !vp ) { // create and add it the first time around.. vp = new VirtualProgram(); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); } #endif // first, update the default shader components based on the new layer count: const ShaderFactory* sf = Registry::instance()->getShaderFactory(); vp->setShader( "osgearth_vert_setupTexturing", sf->createDefaultTextureVertexShader( numImageLayers ) ); // 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 ); } } // not this one, because the compositor always generates a new one. //vp->setShader( "osgearth_frag_applyTexturing", lib.createDefaultTextureFragmentShader( numImageLayers ) ); } // next, inform the compositor that it needs to update based on a new layer count: _texCompositor->updateMasterStateSet( terrainStateSet ); //, numImageLayers ); } }
bool ColorFilterRegistry::writeChain(const ColorFilterChain& chain, Config& out_config) { bool wroteAtLeastOne = false; for( ColorFilterChain::const_iterator i = chain.begin(); i != chain.end(); ++i ) { Config conf = i->get()->getConfig(); if ( !conf.empty() ) { out_config.add( conf ); wroteAtLeastOne = true; } } return wroteAtLeastOne; }
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 ); } }
// 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; } }
// 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; } }
// 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; } }
// 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; } }
// 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::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 ); // Vertex shader template: std::string vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 osg_FrontColor; \n" "varying vec4 osg_FrontSecondaryColor; \n" "varying vec4 oe_layer_tc;\n" "void osgearth_vert_setupColoring() \n" "{ \n" " osg_FrontColor = gl_Color; \n" " osg_FrontSecondaryColor = vec4(0.0);\n" " oe_layer_tc = __GL_MULTITEXCOORD__;\n" "}\n"; // Fragment shader template: std::string fs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_tc; \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" "__COLOR_FILTER_HEAD__" "void osgearth_frag_applyColoring( inout vec4 color ) \n" "{ \n" " vec4 texel = texture2D(oe_layer_tex, oe_layer_tc.st);\n" " float alpha = texel.a * oe_layer_opacity; \n" " if (oe_layer_order == 0) \n" " color = vec4(color.rgb * (1.0 - alpha) + (texel.rgb * alpha), 1.0); \n" " else \n" " color = vec4(texel.rgb, color.a * alpha); \n" " __COLOR_FILTER_BODY__" "} \n"; // install the gl_MultiTexCoord* variable that uses the proper texture // image unit: replaceIn( vs, "__GL_MULTITEXCOORD__", Stringify() << "gl_MultiTexCoord" << _textureImageUnit ); // assemble color filter code snippets. { std::stringstream cf_head; std::stringstream cf_body; // second, install the per-layer color filter functions. bool ifStarted = false; const char* I = " "; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { 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() << "(in int slot, inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(" << _textureImageUnit << ", color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs, "__COLOR_FILTER_BODY__", cf_body_str ); } vp->setShader( "osgearth_vert_setupColoring", new osg::Shader( osg::Shader::VERTEX, vs ), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); vp->setShader( "osgearth_frag_applyColoring", new osg::Shader( osg::Shader::FRAGMENT, fs ), osg::StateAttribute::ON | osg::StateAttribute::PROTECTED ); // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // blend multipass image layers terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), 1); // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _textureImageUnit ); // 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) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( 0 ); // 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; } }