// Build the stateset necessary for drawing contours. osg::StateSet* createStateSet( osg::TransferFunction1D* xfer, int unit ) { osg::StateSet* stateSet = new osg::StateSet(); // Create a 1D texture from the transfer function's image. osg::Texture* tex = new osg::Texture1D( xfer->getImage() ); tex->setResizeNonPowerOfTwoHint( false ); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE ); stateSet->setTextureAttributeAndModes( unit, tex, osg::StateAttribute::ON ); // Tell the shader program where to find it. stateSet->getOrCreateUniform( "contour_colorMap", osg::Uniform::SAMPLER_1D )->set( unit ); // Install the shaders. We also bind osgEarth's elevation data attribute, which the // terrain engine automatically generates at the specified location. VirtualProgram* vp = new VirtualProgram(); vp->installDefaultColoringAndLightingShaders(); vp->setFunction( "setupContour", vertexShader, ShaderComp::LOCATION_VERTEX_PRE_LIGHTING ); vp->setFunction( "colorContour", fragmentShader, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); vp->addBindAttribLocation( "osgearth_elevData", osg::Drawable::ATTRIBUTE_6 ); stateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // Install some uniforms that tell the shader the height range of the color map. stateSet->getOrCreateUniform( "contour_xferMin", osg::Uniform::FLOAT )->set( xfer->getMinimum() ); stateSet->getOrCreateUniform( "contour_xferRange", osg::Uniform::FLOAT )->set( xfer->getMaximum() - xfer->getMinimum() ); return stateSet; };
// Build the stateset necessary for scaling elevation data. osg::StateSet* createStateSet() { osg::StateSet* stateSet = new osg::StateSet(); // Install the shaders. We also bind osgEarth's elevation data attribute, which the // terrain engine automatically generates at the specified location. VirtualProgram* vp = new VirtualProgram(); vp->setFunction( "applyVerticalScale", vertexShader, ShaderComp::LOCATION_VERTEX_MODEL ); vp->addBindAttribLocation( "osgearth_elevData", osg::Drawable::ATTRIBUTE_6 ); stateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); return stateSet; };
void configure(int slot, unsigned numInstances) { _slot = slot; _numInstances = numInstances; osg::StateSet* ss = getOrCreateStateSet(); _xfb->resizeArray( numInstances ); VirtualProgram* vp = VirtualProgram::get(ss); vp->removeBindAttribLocation( "xfb_position" ); vp->addBindAttribLocation( "xfb_position", _slot ); ss->setAttribute( new osg::VertexAttribDivisor(_slot, 1) ); _drawCallback = new InstanceDrawCallback(); Setup setup(this); this->accept( setup ); }
// 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 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; } }
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 ); }
void makeVisibleVP(osg::StateSet* ss) { VirtualProgram* vp = VirtualProgram::getOrCreate(ss); vp->setFunction("oe_instancing_setPos", IG_VS, ShaderComp::LOCATION_VERTEX_MODEL, -FLT_MAX); vp->addBindAttribLocation( "xfb_position", XFB_SLOT ); }
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) ); }
// 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; } }
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->setName("GPU Clamping"); 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 ); // install a VP on the stateset that cancels out any higher-up VP code. // This will prevent things like VPs on the main camera (e.g., log depth buffer) // from interfering with the depth camera VirtualProgram* rttVP = VirtualProgram::getOrCreate(rttStateSet); rttVP->setInheritShaders(false); // 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->_horizonDistance2Uniform = local->_groupStateSet->getOrCreateUniform( "oe_clamp_horizonDistance2", 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 // default value for altitude offset; can be overriden by geometry. local->_groupStateSet->addUniform( new osg::Uniform(Clamping::AltitudeOffsetUniformName, 0.0f) ); // make the shader that will do clamping and depth offsetting. VirtualProgram* vp = VirtualProgram::getOrCreate(local->_groupStateSet.get()); vp->setName( "GPUClamping" ); // Bind clamping attribute location, and a default uniform indicating whether // they are available (default is false). vp->addBindAttribLocation( Clamping::AnchorAttrName, Clamping::AnchorAttrLocation ); local->_groupStateSet->addUniform( new osg::Uniform(Clamping::HasAttrsUniformName, false) ); // Bind clamping heights location. vp->addBindAttribLocation( Clamping::HeightsAttrName, Clamping::HeightsAttrLocation ); osgEarth::Shaders pkg; pkg.load(vp, pkg.GPUClampingVertex); pkg.load(vp, pkg.GPUClampingFragment); }