// 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; } }