Пример #1
0
TileBuilder::Job*
TileBuilder::createJob( const TileKey& key, Threading::MultiEvent& semaphore )
{
    Job* job = new Job( key, _map );

    // create the image layer tasks:
    for( ImageLayerVector::const_iterator i = job->_mapf.imageLayers().begin(); i != job->_mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() && layer->isKeyValid(key) )
        {
            ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore );
            j->init( key, layer, job->_mapf.getMapInfo(), _terrainOptions, job->_repo );
            j->setPriority( -(float)key.getLevelOfDetail() );
            job->_tasks.push_back( j );
        }
    }

    // If we have elevation layers, start an elevation job as well. Otherwise just create an
    // empty one while we're waiting for the images to load.
    if ( job->_mapf.elevationLayers().size() > 0 )
    {
        ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore );
        ej->init( key, job->_mapf, _terrainOptions, job->_repo );
        ej->setPriority( -(float)key.getLevelOfDetail() );
        job->_tasks.push_back( ej );
    }

    return job;
}
Пример #2
0
void
TileModelFactory::createTileModel(const TileKey&           key, 
                                  const MapFrame&          frame,
                                  bool                     accumulate,
                                  osg::ref_ptr<TileModel>& out_model,
                                  ProgressCallback*        progress)
{

    osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() );

    model->_useParentData = _terrainReqs->parentTexturesRequired();

    model->_tileKey = key;
    model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo());

    OE_START_TIMER(fetch_imagery);

    // Fetch the image data and make color layers.
    unsigned index = 0;
    unsigned order = 0;
    for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() && layer->isKeyInRange(key) )
        {
            BuildColorData build;
            build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, _liveTiles.get(), model.get() );

            bool addedToModel = build.execute(progress);
            if ( addedToModel )
            {
                // only bump the order if we added something to the data model.
                order++;
            }
        }
    }

    if (progress)
        progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_imagery);

    
    // make an elevation layer.
    OE_START_TIMER(fetch_elevation);
    buildElevation(key, frame, accumulate, _terrainReqs->elevationTexturesRequired(), model.get(), progress);
    if (progress)
        progress->stats()["fetch_elevation_time"] += OE_STOP_TIMER(fetch_elevation);
    
    // make a normal map layer (if necessary)
    if ( _terrainReqs->normalTexturesRequired() )
    {
        OE_START_TIMER(fetch_normalmap);
        buildNormalMap(key, frame, accumulate, model.get(), progress);
        if (progress)
            progress->stats()["fetch_normalmap_time"] += OE_STOP_TIMER(fetch_normalmap);
    }

    // If nothing was added, not even a fallback heightfield, something went
    // horribly wrong. Leave without a tile model. Chances are that a parent tile
    // not not found in the live-tile registry.
    if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it
    // as fallback data of course)
    if ( !model->_elevationData.getHeightField() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 );
        model->_elevationData = TileModel::ElevationData(
            hf,
            GeoLocator::createForKey(key, frame.getMapInfo()),
            true );
    }

    // look up the parent model and cache it.
    osg::ref_ptr<TileNode> parentTile;
    if ( _liveTiles->get(key.createParentKey(), parentTile) )
    {
        model->_parentModel = parentTile->getTileModel();
    }

    out_model = model.release();
}
Пример #3
0
// 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;
    }
}
Пример #4
0
// 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;
    }
}
Пример #5
0
void
Map::calculateProfile()
{
    if ( !_profile.valid() )
    {
        osg::ref_ptr<const Profile> userProfile;
        if ( _mapOptions.profile().isSet() )
        {
            userProfile = Profile::create( _mapOptions.profile().value() );
        }

        if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC )
        {
            if ( userProfile.valid() )
            {
                if ( userProfile->isOK() && userProfile->getSRS()->isGeographic() )
                {
                    _profile = userProfile.get();
                }
                else
                {
                    OE_WARN << LC 
                        << "Map is geocentric, but the configured profile SRS ("
                        << userProfile->getSRS()->getName() << ") is not geographic; "
                        << "it will be ignored."
                        << std::endl;
                }
            }

            if ( !_profile.valid() )
            {
                // by default, set a geocentric map to use global-geodetic WGS84.
                _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile();
            }
        }

        else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE )
        {
            //If the map type is a Geocentric Cube, set the profile to the cube profile.
            _profile = osgEarth::Registry::instance()->getCubeProfile();
        }

        else // CSTYPE_PROJECTED
        {
            if ( userProfile.valid() )
            {
                _profile = userProfile.get();
            }
        }

        // At this point, if we don't have a profile we need to search tile sources until we find one.
        if ( !_profile.valid() )
        {
            Threading::ScopedReadLock lock( _mapDataMutex );

            for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end() && !_profile.valid(); i++ )
            {
                ImageLayer* layer = i->get();
                if ( layer->getTileSource() )
                {
                    _profile = layer->getTileSource()->getProfile();
                }
            }

            for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end() && !_profile.valid(); i++ )
            {
                ElevationLayer* layer = i->get();
                if ( layer->getTileSource() )
                {
                    _profile = layer->getTileSource()->getProfile();
                }
            }
        }

        // convert the profile to Plate Carre if necessary.
        if (_profile.valid() &&
            _profile->getSRS()->isGeographic() && 
            getMapOptions().coordSysType() == MapOptions::CSTYPE_PROJECTED )
        {
            OE_INFO << LC << "Projected display with geographic SRS; activating Plate Carre mode" << std::endl;
            _profile = _profile->overrideSRS( _profile->getSRS()->createPlateCarreGeographicSRS() );
        }

        // finally, fire an event if the profile has been set.
        if ( _profile.valid() )
        {
            OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl;

            for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ )
            {
                i->get()->onMapInfoEstablished( MapInfo(this) );
            }
        }

        else
        {
            OE_WARN << LC << "Warning, not yet able to establish a map profile!" << std::endl;
        }
    }

    if ( _profile.valid() )
    {
        // tell all the loaded layers what the profile is, as a hint
        {
            Threading::ScopedWriteLock lock( _mapDataMutex );

            for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++ )
            {
                ImageLayer* layer = i->get();
                if ( layer->getEnabled() == true )
                {
                    layer->setTargetProfileHint( _profile.get() );
                }
            }

            for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); i++ )
            {
                ElevationLayer* layer = i->get();
                if ( layer->getEnabled() )
                {
                    layer->setTargetProfileHint( _profile.get() );
                }
            }
        }

        // create a "proxy" profile to use when querying elevation layers with a vertical datum
        if ( _profile->getSRS()->getVerticalDatum() != 0L )
        {
            ProfileOptions po = _profile->toProfileOptions();
            po.vsrsString().unset();
            _profileNoVDatum = Profile::create(po);
        }
        else
        {
            _profileNoVDatum = _profile;
        }
    }
}
Пример #6
0
void
TileBuilder::createTile(const TileKey&      key, 
                        bool                parallelize, 
                        osg::ref_ptr<Tile>& out_tile, 
                        bool&               out_hasRealData,
                        bool&               out_hasLodBlendedLayers )
{
    MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS );

    SourceRepo repo;

    // init this to false, then search for real data. "Real data" is data corresponding
    // directly to the key, as opposed to fallback data, which is derived from a lower
    // LOD key.
    out_hasRealData = false;
    out_hasLodBlendedLayers = false;

    const MapInfo& mapInfo = mapf.getMapInfo();

    // If we need more than one layer, fetch them in parallel.
    // TODO: change the test based on isKeyValid total.
    if ( parallelize && (mapf.imageLayers().size() + mapf.elevationLayers().size() > 1) )
    {
        // count the valid layers.
        int jobCount = 0;

        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            if ( i->get()->isKeyValid( key ) )
                ++jobCount;

            if ( i->get()->getImageLayerOptions().lodBlending() == true )
                out_hasLodBlendedLayers = true;
        }

        if ( mapf.elevationLayers().size() > 0 )
            ++jobCount;

        // A thread job monitoring event:
        Threading::MultiEvent semaphore( jobCount );

        // Start the image layer jobs:
        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            if ( layer->isKeyValid(key) )
            {
                ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore );
                j->init( key, layer, mapInfo, _terrainOptions, repo );
                j->setPriority( -(float)key.getLevelOfDetail() );
                _service->add( j );
            }
        }

        // If we have elevation layers, start an elevation job as well. Otherwise just create an
        // empty one while we're waiting for the images to load.
        if ( mapf.elevationLayers().size() > 0 )
        {
            ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore );
            ej->init( key, mapf, _terrainOptions, repo );
            ej->setPriority( -(float)key.getLevelOfDetail() );
            _service->add( ej );
        }
        else
        {
            BuildElevLayer build;
            build.init( key, mapf, _terrainOptions, repo );
            build.execute();
        }

        // Wait for all the jobs to finish.
        semaphore.wait();
    }
    
    // Fetch the image data serially:
    else
    {
        // gather all the image layers serially.
        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            //if ( layer->isKeyValid(key) )  // Wrong. no guarantee key is in the same profile.

            if ( layer->getEnabled() )
            {
                BuildColorLayer build;
                build.init( key, layer, mapInfo, _terrainOptions, repo );
                build.execute();

                if ( layer->getImageLayerOptions().lodBlending() == true )
                    out_hasLodBlendedLayers = true;
            }
        }
        
        // make an elevation layer.
        BuildElevLayer build;
        build.init( key, mapf, _terrainOptions, repo );
        build.execute();
    }

    // Bail out now if there's no data to be had.
    if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !repo._elevLayer.getHFLayer() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 );
        //osg::HeightField* hf = key.getProfile()->getVerticalSRS()->createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        repo._elevLayer = CustomElevLayer( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() && !layer->isKeyValid(key) )
        {
            if ( !emptyImage.valid() )
                emptyImage = ImageUtils::createEmptyImage();

            repo.add( CustomColorLayer(
                layer,
                emptyImage.get(),
                locator,
                key.getLevelOfDetail(),
                key,
                true ) );
        }
    }

    //osg::Vec3dArray* maskBounds = 0L;
    //osgEarth::MaskLayer* mask = mapf.getTerrainMaskLayer();
    //if (mask)
    //  maskBounds = mask->getOrCreateBoundary();

    // Ready to create the actual tile.
    AssembleTile assemble;
    assemble.init( key, mapInfo, _terrainOptions, repo, mapf.terrainMaskLayers() );
    assemble.execute();

    if (!out_hasRealData)
    {
        // Check the results and see if we have any real data.
        for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i )
        {
            if ( !i->second.isFallbackData() ) 
            {
                out_hasRealData = true;
                break;
            }
        }
    }

    if ( !out_hasRealData && !repo._elevLayer.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_tile = assemble._tile;
}
Пример #7
0
void
TileBuilder::finalizeJob(TileBuilder::Job*   job, 
                         osg::ref_ptr<Tile>& out_tile,
                         bool&               out_hasRealData,
                         bool&               out_hasLodBlending)
{
    SourceRepo& repo = job->_repo;

    out_hasRealData = false;
    out_hasLodBlending = false;

    // Bail out now if there's no data to be had.
    if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() )
    {
        return;
    }

    const TileKey& key = job->_key;
    const MapInfo& mapInfo = job->_mapf.getMapInfo();

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !repo._elevLayer.getHFLayer() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        repo._elevLayer = CustomElevLayer( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = job->_mapf.imageLayers().begin(); i != job->_mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() )
        {
            if ( !layer->isKeyValid(key) )
            {
                if ( !emptyImage.valid() )
                    emptyImage = ImageUtils::createEmptyImage();

                repo.add( CustomColorLayer(
                    i->get(), emptyImage.get(),
                    locator,
                    key.getLevelOfDetail(),
                    key,
                    true ) );
            }

            if ( i->get()->getImageLayerOptions().lodBlending() == true )
                out_hasLodBlending = true;
        }
    }

    // Ready to create the actual tile.
    AssembleTile assemble;
    assemble.init( key, mapInfo, _terrainOptions, repo );
    assemble.execute();

    // Check the results and see if we have any real data.
    for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i )
    {
        if ( !i->second.isFallbackData() ) 
        {
            out_hasRealData = true;
            break;
        }
    }
    if ( !out_hasRealData && !repo._elevLayer.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_tile = assemble._tile;
}
Пример #8
0
// 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;
    }
}
Пример #9
0
void
TileModelFactory::createTileModel(const TileKey&           key, 
                                  const MapFrame&          frame,
                                  osg::ref_ptr<TileModel>& out_model) //,
                                  //bool&                    out_hasRealData)
{

    osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() );
    model->_tileKey = key;
    model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo());
    
    // Fetch the image data and make color layers.
    unsigned order = 0;
    for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() )
        {
            BuildColorData build;
            build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, model.get() );
            
            bool addedToModel = build.execute();
            if ( addedToModel )
            {
                // only bump the order if we added something to the data model.
                order++;
            }
        }
    }

    // make an elevation layer.
    BuildElevationData build;
    build.init( key, frame, _terrainOptions, model.get(), _hfCache );
    build.execute();


    // Bail out now if there's no data to be had.
    if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it
    // as fallback data of course)
    if ( !model->_elevationData.getHeightField() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 );
        model->_elevationData = TileModel::ElevationData(
            hf,
            GeoLocator::createForKey(key, frame.getMapInfo()),
            true );
    }

    // look up the parent model and cache it.
    osg::ref_ptr<TileNode> parentTile;
    if ( _liveTiles->get(key.createParentKey(), parentTile) )
        model->_parentModel = parentTile->getTileModel();

    out_model = model.release();
}
Пример #10
0
// 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;
    }
}
Пример #11
0
// 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;
    }
}
Пример #12
0
void
TileModelFactory::createTileModel(const TileKey&           key, 
                                  osg::ref_ptr<TileModel>& out_model,
                                  bool&                    out_hasRealData,
                                  bool&                    out_hasLodBlendedLayers )
{
    MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS );
    
    const MapInfo& mapInfo = mapf.getMapInfo();

    osg::ref_ptr<TileModel> model = new TileModel();
    model->_tileKey = key;
    model->_tileLocator = GeoLocator::createForKey(key, mapInfo);

    // init this to false, then search for real data. "Real data" is data corresponding
    // directly to the key, as opposed to fallback data, which is derived from a lower
    // LOD key.
    out_hasRealData = false;
    out_hasLodBlendedLayers = false;
    
    // Fetch the image data and make color layers.
    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() )
        {
            BuildColorData build;
            build.init( key, layer, mapInfo, _terrainOptions, model.get() );
            build.execute();

            if ( layer->getImageLayerOptions().lodBlending() == true )
            {
                out_hasLodBlendedLayers = true;
            }
        }
    }

    // make an elevation layer.
    BuildElevationData build;
    build.init( key, mapf, _terrainOptions, model.get(), _hfCache );
    build.execute();


    // Bail out now if there's no data to be had.
    if ( model->_colorData.size() == 0 && !model->_elevationData.getHFLayer() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !model->_elevationData.getHFLayer() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 );
        osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf );
        hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) );
        model->_elevationData = TileModel::ElevationData( hfLayer, true );
    }

    // Now, if there are any color layers that did not get built, create them with an empty
    // image so the shaders have something to draw.
    osg::ref_ptr<osg::Image> emptyImage;
    osgTerrain::Locator* locator = model->_elevationData.getHFLayer()->getLocator();

    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() && !layer->isKeyValid(key) )
        {
            if ( !emptyImage.valid() )
                emptyImage = ImageUtils::createEmptyImage();

            model->_colorData[i->get()->getUID()] = TileModel::ColorData(
                layer,
                emptyImage.get(),
                locator,
                key.getLevelOfDetail(),
                key,
                true );
        }
    }

    // Ready to create the actual tile.
    //AssembleTile assemble;
    //assemble.init( key, mapInfo, _terrainOptions, model.get(), mapf.terrainMaskLayers() );
    //assemble.execute();

    // if we're using LOD blending, find and add the parent's state set.
    if ( out_hasLodBlendedLayers && key.getLevelOfDetail() > 0 && _liveTiles.valid() )
    {
        osg::ref_ptr<TileNode> parent;
        if ( _liveTiles->get( key.createParentKey(), parent ) )
        {
            model->_parentStateSet = parent->getPublicStateSet();
        }
    }

    if (!out_hasRealData)
    {
        // Check the results and see if we have any real data.
        for( TileModel::ColorDataByUID::const_iterator i = model->_colorData.begin(); i != model->_colorData.end(); ++i )
        {
            if ( !i->second.isFallbackData() ) 
            {
                out_hasRealData = true;
                break;
            }
        }
    }

    if ( !out_hasRealData && !model->_elevationData.isFallbackData() )
    {
        out_hasRealData = true;
    }

    out_model = model.release();
    //out_tile = assemble._node;
}
Пример #13
0
void
TerrainEngineNode::updateImageUniforms()
{
    // don't bother if this is a hurting old card
    if ( !Registry::instance()->getCapabilities().supportsGLSL() )
        return;

    // update the layer uniform arrays:
    osg::StateSet* stateSet = this->getOrCreateStateSet();

    // get a copy of the image layer stack:
    MapFrame mapf( _map.get(), Map::IMAGE_LAYERS );

    _imageLayerController->_layerEnabledUniform.detach();
    _imageLayerController->_layerOpacityUniform.detach();
    _imageLayerController->_layerRangeUniform.detach();

#if 0
    if ( _imageLayerController->_layerEnabledUniform.valid() )
        _imageLayerController->_layerEnabledUniform->removeFrom( stateSet );

    if ( _imageLayerController->_layerOpacityUniform.valid() )
        _imageLayerController->_layerOpacityUniform->removeFrom( stateSet );

    if ( _imageLayerController->_layerRangeUniform.valid() )
        _imageLayerController->_layerRangeUniform->removeFrom( stateSet );
#endif

    //stateSet->removeUniform( "osgearth_ImageLayerAttenuation" );
    
    if ( mapf.imageLayers().size() > 0 )
    {
        // the "enabled" uniform is fixed size. this is handy to account for layers that are in flux...i.e., their source
        // layer count has changed, but the shader has not yet caught up. In the future we might use this to disable
        // "ghost" layers that used to exist at a given index, but no longer do.
        
        _imageLayerController->_layerEnabledUniform.attach( "osgearth_ImageLayerEnabled", osg::Uniform::BOOL,  stateSet, 64 );
        _imageLayerController->_layerOpacityUniform.attach( "osgearth_ImageLayerOpacity", osg::Uniform::FLOAT, stateSet, mapf.imageLayers().size() );
        _imageLayerController->_layerRangeUniform.attach  ( "osgearth_ImageLayerRange",   osg::Uniform::FLOAT, stateSet, 2 * mapf.imageLayers().size() );

        //_imageLayerController->_layerEnabledUniform  = new ArrayUniform( osg::Uniform::BOOL,  "osgearth_ImageLayerEnabled", 64 ); //mapf.imageLayers().size() );
        //_imageLayerController->_layerOpacityUniform  = new ArrayUniform( osg::Uniform::FLOAT, "osgearth_ImageLayerOpacity", mapf.imageLayers().size() );
        //_imageLayerController->_layerRangeUniform    = new ArrayUniform( osg::Uniform::FLOAT, "osgearth_ImageLayerRange", 2 * mapf.imageLayers().size() );

        for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
        {
            ImageLayer* layer = i->get();
            int index = (int)(i - mapf.imageLayers().begin());

            _imageLayerController->_layerOpacityUniform.setElement( index, layer->getOpacity() );
            _imageLayerController->_layerEnabledUniform.setElement( index, layer->getEnabled() );
            _imageLayerController->_layerRangeUniform.setElement( (2*index), layer->getImageLayerOptions().minVisibleRange().value() );
            _imageLayerController->_layerRangeUniform.setElement( (2*index)+1, layer->getImageLayerOptions().maxVisibleRange().value() );
        }

        // set the remainder of the layers to disabled 
        for( int j=mapf.imageLayers().size(); j<64; ++j )
            _imageLayerController->_layerEnabledUniform.setElement( j, false );

        //_imageLayerController->_layerOpacityUniform->addTo( stateSet );
        //_imageLayerController->_layerEnabledUniform->addTo( stateSet );
        //_imageLayerController->_layerRangeUniform->addTo( stateSet );
    }
}
Пример #14
0
void
TileModelFactory::createTileModel(const TileKey&           key, 
                                  osg::ref_ptr<TileModel>& out_model,
                                  bool&                    out_hasRealData)
{
    MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS );
    
    const MapInfo& mapInfo = mapf.getMapInfo();

    osg::ref_ptr<TileModel> model = new TileModel();
    model->_map         = _map;
    model->_tileKey     = key;
    model->_tileLocator = GeoLocator::createForKey(key, mapInfo);

    // init this to false, then search for real data. "Real data" is data corresponding
    // directly to the key, as opposed to fallback data, which is derived from a lower
    // LOD key.
    out_hasRealData = false;
    
    // Fetch the image data and make color layers.
    unsigned order = 0;
    for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
    {
        ImageLayer* layer = i->get();

        if ( layer->getEnabled() )
        {
            BuildColorData build;
            build.init( key, layer, order, mapInfo, _terrainOptions, model.get() );
            
            bool addedToModel = build.execute();
            if ( addedToModel )
            {
                // only bump the order if we added something to the data model.
                order++;
            }
        }
    }

    // make an elevation layer.
    BuildElevationData build;
    build.init( key, mapf, _terrainOptions, model.get(), _hfCache );
    build.execute();


    // Bail out now if there's no data to be had.
    if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() )
    {
        return;
    }

    // OK we are making a tile, so if there's no heightfield yet, make an empty one.
    if ( !model->_elevationData.getHeightField() )
    {
        osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 );
        model->_elevationData = TileModel::ElevationData(
            hf,
            GeoLocator::createForKey(key, mapInfo),
            true );
    }

    if (!out_hasRealData)
    {
        // Check the results and see if we have any real data.
        for( TileModel::ColorDataByUID::const_iterator i = model->_colorData.begin(); i != model->_colorData.end(); ++i )
        {
            if ( !i->second.isFallbackData() ) 
            {
                out_hasRealData = true;
                break;
            }
        }
    }

    if ( !out_hasRealData && !model->_elevationData.isFallbackData() )
    {
        out_hasRealData = true;
    }

    // look up the parent model and cache it.
    osg::ref_ptr<TileNode> parentTile;
    if ( _liveTiles->get(key.createParentKey(), parentTile) )
        model->_parentModel = parentTile->getTileModel();

    out_model = model.release();
}
Пример #15
0
int
main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc,argv);

    // Which filter?
    bool useHSL   = arguments.read("--hsl");
    bool useRGB   = arguments.read("--rgb");
    bool useCMYK  = arguments.read("--cmyk");
    bool useBC    = arguments.read("--bc");
    bool useGamma = arguments.read("--gamma");
    bool useChromaKey = arguments.read("--chromakey");

    if ( !useHSL && !useRGB && !useCMYK && !useBC && !useGamma && !useChromaKey )
    {
        return usage( "Please select one of the filter options!" );
    }

    osgViewer::Viewer viewer(arguments);
    viewer.setCameraManipulator( new EarthManipulator() );

    // load an earth file
    osg::Node* node = MapNodeHelper().load(arguments, &viewer);
    if ( !node )
        return usage( "Unable to load map from earth file!" );
    viewer.setSceneData( node );

    //Create the control panel
    Container* box = createControlPanel(&viewer);
    
    osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( node );
    if ( node )
    {   
        if (mapNode->getMap()->getNumImageLayers() == 0)
        {
            return usage("Please provide a map with at least one image layer.");
        }

        // attach color filter to each layer.
        unsigned numLayers = mapNode->getMap()->getNumImageLayers();
        for( unsigned i=0; i<numLayers; ++i )
        {
            ImageLayer* layer = mapNode->getMap()->getImageLayerAt( i );

            if ( layer->getEnabled() && layer->getVisible() )
            {
                if ( useHSL )
                {
                    HSLColorFilter* filter = new HSLColorFilter();
                    layer->addColorFilter( filter );
                    HSL::addControls( filter, box, i );
                }
                else if ( useRGB )
                {
                    RGBColorFilter* filter = new RGBColorFilter();
                    layer->addColorFilter( filter );
                    RGB::addControls( filter, box, i );
                }
                else if ( useCMYK )
                {
                    CMYKColorFilter* filter = new CMYKColorFilter();
                    layer->addColorFilter( filter );
                    CMYK::addControls( filter, box, i );
                }
                else if ( useBC )
                {
                    BrightnessContrastColorFilter* filter = new BrightnessContrastColorFilter();
                    layer->addColorFilter( filter );
                    BC::addControls( filter, box, i );
                }
                else if ( useGamma )
                {
                    GammaColorFilter* filter = new GammaColorFilter();
                    layer->addColorFilter( filter );
                    GAMMA::addControls( filter, box, i );
                }
                else if ( useChromaKey )
                {
                    ChromaKeyColorFilter* filter = new ChromaKeyColorFilter();
                    layer->addColorFilter( filter );
                    CHROMAKEY::addControls( filter, box , i );
                }
            }
        }
    }
    

    return viewer.run();
}
Пример #16
0
// 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;
    }
}
Пример #17
0
/** Packages image and elevation layers as a TMS. */
int TMSExporter::exportTMS(MapNode* mapNode, const std::string& path, std::vector< osgEarth::Bounds >& bounds, const std::string& outEarth, bool overwrite, const std::string& extension)
{
  if ( !mapNode )
  {
    _errorMessage = "Invalid MapNode";
    if (_progress.valid()) _progress->onCompleted();
    return 0;
  }

  // folder to which to write the TMS archive.
  std::string rootFolder = path;

  osg::ref_ptr<osgDB::Options> options = new osgDB::Options(_dbOptions);

  // create a folder for the output
  osgDB::makeDirectory(rootFolder);
  if ( !osgDB::fileExists(rootFolder) )
  {
    _errorMessage = "Failed to create root output folder";
    if (_progress.valid()) _progress->onCompleted();
    return 0;
  }

  Map* map = mapNode->getMap();

  // new map for an output earth file if necessary.
  osg::ref_ptr<Map> outMap = 0L;
  if ( !outEarth.empty() )
  {
      // copy the options from the source map first
      outMap = new Map(map->getInitialMapOptions());
  }

  // establish the output path of the earth file, if applicable:
  std::string outEarthName = osgDB::getSimpleFileName(outEarth);
  if (outEarthName.length() > 0 && osgEarth::toLower(osgDB::getFileExtension(outEarthName)) != "earth")
    outEarthName += ".earth";

  std::string outEarthFile = osgDB::concatPaths(rootFolder, outEarthName);
  

  // semaphore and tasks collection for multithreading
  osgEarth::Threading::MultiEvent semaphore;
  osgEarth::TaskRequestVector tasks;
  int taskCount = 0;


  // package any image layers that are enabled and visible
  ImageLayerVector imageLayers;
  map->getImageLayers( imageLayers );

  unsigned imageCount = 0;
  for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++imageCount )
  {
      ImageLayer* layer = i->get();

      if ( layer->getEnabled() && layer->getVisible() )
      {
          std::string layerFolder = toLegalFileName( layer->getName() );
          if ( layerFolder.empty() )
              layerFolder = Stringify() << "image_layer_" << imageCount;

          ParallelTask<PackageLayer>* task = new ParallelTask<PackageLayer>( &semaphore );
          task->init(map, layer, options, rootFolder, layerFolder, true, overwrite, _keepEmpties, _maxLevel, extension, bounds);
          task->setProgressCallback(new PackageLayerProgressCallback(this));
          tasks.push_back(task);
          taskCount++;
      }
  }

  // package any elevation layers that are enabled and visible
  ElevationLayerVector elevationLayers;
  map->getElevationLayers( elevationLayers );

  int elevCount = 0;
  for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++elevCount )
  {
      ElevationLayer* layer = i->get();
      if ( layer->getEnabled() && layer->getVisible() )
      {
          std::string layerFolder = toLegalFileName( layer->getName() );
          if ( layerFolder.empty() )
              layerFolder = Stringify() << "elevation_layer_" << elevCount;

          ParallelTask<PackageLayer>* task = new ParallelTask<PackageLayer>( &semaphore );
          task->init(map, layer, options, rootFolder, layerFolder, true, overwrite, _keepEmpties, _maxLevel, extension, bounds);
          task->setProgressCallback(new PackageLayerProgressCallback(this));
          tasks.push_back(task);
          taskCount++;
      }
  }


  // Run all the tasks in parallel
  _totalTasks = taskCount;
  _completedTasks = 0;

  semaphore.reset( _totalTasks );

  for( TaskRequestVector::iterator i = tasks.begin(); i != tasks.end(); ++i )
        _taskService->add( i->get() );

  // Wait for them to complete
  semaphore.wait();


  // Add successfully packaged layers to the new map object and
  // write out the .earth file (if requested)
  if (outMap.valid())
  {
    for( TaskRequestVector::iterator i = tasks.begin(); i != tasks.end(); ++i )
    {
      PackageLayer* p = dynamic_cast<PackageLayer*>(i->get());
      if (p)
      {
        if (p->_packageResult.ok)
        {
          TMSOptions tms;
          tms.url() = URI(osgDB::concatPaths(p->_layerFolder, "tms.xml"), outEarthFile );

          if (p->_imageLayer.valid())
          {
            ImageLayerOptions layerOptions( p->_imageLayer->getName(), tms );
            layerOptions.mergeConfig( p->_imageLayer->getInitialOptions().getConfig(true) );
            layerOptions.cachePolicy() = CachePolicy::NO_CACHE;

            outMap->addImageLayer( new ImageLayer(layerOptions) );
          }
          else
          {
            ElevationLayerOptions layerOptions( p->_elevationLayer->getName(), tms );
            layerOptions.mergeConfig( p->_elevationLayer->getInitialOptions().getConfig(true) );
            layerOptions.cachePolicy() = CachePolicy::NO_CACHE;

            outMap->addElevationLayer( new ElevationLayer(layerOptions) );
          }
        }
        else
        {
          OE_WARN << LC << p->_packageResult.message << std::endl;
        }
      }
    }
  }

  if ( outMap.valid() )
  {
      MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions();
      osg::ref_ptr<MapNode> outMapNode = new MapNode(outMap.get(), outNodeOptions);
      if ( !osgDB::writeNodeFile(*outMapNode.get(), outEarthFile) )
      {
          OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl;
      }
      else
      {
          OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl;
      }
  }


  // Mark the progress callback as completed
  if (_progress.valid()) _progress->onCompleted();

  return elevCount + imageCount;
}