void
OSGTerrainEngineNode::updateTextureCombining()
{
    if ( _texCompositor.valid() )
    {
        int numImageLayers = _update_mapf->imageLayers().size();
        osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet();

        if ( _texCompositor->usesShaderComposition() )
        {
            // Creates or updates the shader components that are generated by the texture compositor.
            // These components reside in the CustomTerrain's stateset, and override the components
            // installed in the VP on the engine-node's stateset in installShaders().

            VirtualProgram* vp = dynamic_cast<VirtualProgram*>( terrainStateSet->getAttribute(osg::StateAttribute::PROGRAM) );
            if ( !vp )
            {
                // create and add it the first time around..
                vp = new VirtualProgram();
                terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON );
            }

            // first, update the default shader components based on the new layer count:
            const ShaderFactory* sf = Registry::instance()->getShaderFactory();
            vp->setShader( "osgearth_vert_setupTexturing",  sf->createDefaultTextureVertexShader( numImageLayers ) );

            // not this one, because the compositor always generates a new one.
            //vp->setShader( "osgearth_frag_applyTexturing",  lib.createDefaultTextureFragmentShader( numImageLayers ) );
        }

        // next, inform the compositor that it needs to update based on a new layer count:
        _texCompositor->updateMasterStateSet( terrainStateSet ); //, numImageLayers );
    }
}
void
TextureCompositorTexArray::updateMasterStateSet( osg::StateSet* stateSet, const TextureLayout& layout ) const
{
    VirtualProgram* vp = static_cast<VirtualProgram*>( stateSet->getAttribute(osg::StateAttribute::PROGRAM) );

    vp->setShader( 
        "osgearth_frag_applyTexturing", 
        s_createTextureFragShaderFunction(layout, true, _lodTransitionTime ) );
}
void
HSLColorFilter::install( osg::StateSet* stateSet ) const
{
    // safe: won't add twice.
    stateSet->addUniform( _hsl.get() );

    VirtualProgram* vp = dynamic_cast<VirtualProgram*>(stateSet->getAttribute(VirtualProgram::SA_TYPE));
    if ( vp )
    {
        // safe: won't add the same pointer twice.
        vp->setShader( "osgEarthUtil::HSLColorFilter_common", s_commonShader.get() );

        // build the local shader (unique per instance). We'll use a template with search
        // and replace for this one.
        std::string entryPoint = Stringify() << FUNCTION_PREFIX << _instanceId;
        std::string code       = s_localShaderSource;
        replaceIn( code, "__UNIFORM_NAME__", _hsl->getName() );
        replaceIn( code, "__ENTRY_POINT__",  entryPoint );

        osg::Shader* main = new osg::Shader(osg::Shader::FRAGMENT, code);
        //main->setName(entryPoint);
        vp->setShader(entryPoint, main);
    }
}
void
OSGTerrainEngineNode::updateTextureCombining()
{
    if ( _texCompositor.valid() )
    {
        int numImageLayers = _update_mapf->imageLayers().size();
        osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet();

        if ( _texCompositor->usesShaderComposition() )
        {
            // Creates or updates the shader components that are generated by the texture compositor.
            // These components reside in the CustomTerrain's stateset, and override the components
            // installed in the VP on the engine-node's stateset in installShaders().

            VirtualProgram* vp = new VirtualProgram() ;
            vp->setName( "engine_osgterrain:TerrainNode" );
            vp->installDefaultColoringShaders(numImageLayers);

            terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON );

            // first, update the default shader components based on the new layer count:
            const ShaderFactory* sf = Registry::instance()->getShaderFactory();
            
            // second, install the per-layer color filter functions.
            for( int i=0; i<numImageLayers; ++i )
            {
                std::string layerFilterFunc = Stringify() << "osgearth_runColorFilters_" << i;
                const ColorFilterChain& chain = _update_mapf->getImageLayerAt(i)->getColorFilters();

                // install the wrapper function that calls all the filters in turn:
                vp->setShader( layerFilterFunc, sf->createColorFilterChainFragmentShader(layerFilterFunc, chain) );

                // install each of the filter entry points:
                for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j )
                {
                    const ColorFilter* filter = j->get();
                    filter->install( terrainStateSet );
                }
            }
        }

        // next, inform the compositor that it needs to update based on a new layer count:
        _texCompositor->updateMasterStateSet( terrainStateSet ); //, numImageLayers );
    }
}
    // This runs when the color filter is first installed.
    void install(osg::StateSet* stateSet) const
    {
        // When we added the shared layer, osgEarth reserves a special
        // image unit for it. Retrieve that now sine we need it in order
        // to use its sampler.
        int unit = _maskLayer->shareImageUnit().get();

        // Make a vertex shader that will access the texture coordinates
        // for our shared layer.
        std::string vs = Stringify()
            << "varying vec4 mask_layer_texc; \n"
            << "void my_filter_vertex(inout vec4 VertexMODEL) \n"
            << "{ \n"
            << "    mask_layer_texc = gl_MultiTexCoord" << unit << "; \n"
            <<"} \n";

        // Make the fragment shader that will modulate the visible layer.
        // This is is simple -- it just maxes out the red component wherever
        // the shared "mask" layer exceed a certain alpha value.
        std::string fs =
            "uniform sampler2D mask_layer_tex; \n"
            "varying vec4 mask_layer_texc; \n"
            "void my_color_filter(inout vec4 color) \n"
            "{ \n"
            "    vec4 mask_texel = texture2D(mask_layer_tex, mask_layer_texc.st); \n"
            "    if ( mask_texel.a >= 0.5 ) \n"
            "    { \n"
            "        color.r = 1.0; \n"
            "    } \n"
            "} \n";

        // getOrCreate ensures we don't overwrite an existing VP.
        VirtualProgram* vp = VirtualProgram::getOrCreate( stateSet );

        // install the vertex function
        vp->setFunction( "my_filter_vertex",   vs, ShaderComp::LOCATION_VERTEX_MODEL );

        // install the color filter entry point. This is just a regular shader function,
        // not a pipeline injection, so just use setShader.
        vp->setShader( "my_color_filter", new osg::Shader(osg::Shader::FRAGMENT, fs) );

        // finally, bind our sampler uniform to the allocated image unit.
        stateSet->getOrCreateUniform("mask_layer_tex", osg::Uniform::SAMPLER_2D)->set( unit );
    }
void
GroundCoverLayer::buildStateSets()
{
    // assert we have the necessary TIUs:
    if (_groundCoverTexBinding.valid() == false) {
        OE_DEBUG << LC << "buildStateSets deferred.. bindings not reserved\n";
        return;
    }

    if (!_zonesConfigured) {
        OE_DEBUG << LC << "buildStateSets deferred.. zones not yet configured\n";
        return;
    }
    
    osg::ref_ptr<LandCoverDictionary> landCoverDict;
    if (_landCoverDict.lock(landCoverDict) == false) {
        OE_DEBUG << LC << "buildStateSets deferred.. land cover dictionary not available\n";
        return;
    }
    
    osg::ref_ptr<LandCoverLayer> landCoverLayer;
    if (_landCoverLayer.lock(landCoverLayer) == false) {
        OE_DEBUG << LC << "buildStateSets deferred.. land cover layer not available\n";
        return;
    }

    NoiseTextureFactory noise;
    osg::ref_ptr<osg::Texture> noiseTexture = noise.create(256u, 4u);

    GroundCoverShaders shaders;

    // Layer-wide stateset:
    osg::StateSet* stateset = getOrCreateStateSet();

    // bind the noise sampler.
    stateset->setTextureAttribute(_noiseBinding.unit(), noiseTexture.get());
    stateset->addUniform(new osg::Uniform(NOISE_SAMPLER, _noiseBinding.unit()));

    if (_maskLayer.valid())
    {
        stateset->setDefine("OE_GROUNDCOVER_MASK_SAMPLER", _maskLayer->shareTexUniformName().get());
        stateset->setDefine("OE_GROUNDCOVER_MASK_MATRIX", _maskLayer->shareTexMatUniformName().get());
    }

    // disable backface culling to support shadow/depth cameras,
    // for which the geometry shader renders cross hatches instead of billboards.
    stateset->setMode(GL_CULL_FACE, osg::StateAttribute::PROTECTED);

    // enable alpha-to-coverage multisampling for vegetation.
    stateset->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, 1);

    // uniform that communicates the availability of multisampling.
    if (osg::DisplaySettings::instance()->getMultiSamples())
    {
        stateset->setDefine("OE_GROUNDCOVER_HAS_MULTISAMPLES");
    }

    stateset->setAttributeAndModes(
        new osg::BlendFunc(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO),
        osg::StateAttribute::OVERRIDE);


    for (Zones::iterator z = _zones.begin(); z != _zones.end(); ++z)
    {
        Zone* zone = z->get();
        GroundCover* groundCover = zone->getGroundCover();
        if (groundCover)
        {
            if (!groundCover->getBiomes().empty() || groundCover->getTotalNumBillboards() > 0)
            {
                osg::StateSet* zoneStateSet = groundCover->getOrCreateStateSet();
                            
                // Install the land cover shaders on the state set
                VirtualProgram* vp = VirtualProgram::getOrCreate(zoneStateSet);
                vp->setName("Ground cover (" + groundCover->getName() + ")");
                shaders.loadAll(vp, getReadOptions());

                // Generate the coverage acceptor shader
                osg::Shader* covTest = groundCover->createPredicateShader(_landCoverDict.get(), _landCoverLayer.get());
                covTest->setName(covTest->getName() + "_GEOMETRY");
                covTest->setType(osg::Shader::GEOMETRY);
                vp->setShader(covTest);

                osg::Shader* covTest2 = groundCover->createPredicateShader(_landCoverDict.get(), _landCoverLayer.get());
                covTest->setName(covTest->getName() + "_TESSCONTROL");
                covTest2->setType(osg::Shader::TESSCONTROL);
                vp->setShader(covTest2);

                osg::ref_ptr<osg::Shader> layerShader = groundCover->createShader();
                layerShader->setType(osg::Shader::GEOMETRY);
                vp->setShader(layerShader.get());

                OE_INFO << LC << "Established zone \"" << zone->getName() << "\" at LOD " << getLOD() << "\n";

                osg::Texture* tex = groundCover->createTexture();

                zoneStateSet->setTextureAttribute(_groundCoverTexBinding.unit(), tex);
                zoneStateSet->addUniform(new osg::Uniform(GCTEX_SAMPLER, _groundCoverTexBinding.unit()));

                OE_DEBUG << LC << "buildStateSets completed!\n";
            }
            else
            {
                OE_WARN << LC << "ILLEGAL: ground cover layer with no biomes or no billboards defined\n";
            }
        }
        else
        {
            // not an error.
            OE_DEBUG << LC << "zone contains no ground cover information\n";
        }
    }
}
void 
TextureCompositorMultiTexture::updateMasterStateSet(osg::StateSet*       stateSet,
                                                    const TextureLayout& layout    ) const
{
    int numSlots = layout.getMaxUsedSlot() + 1;
    int maxUnits = numSlots;

    if ( _useGPU )
    {
        // Validate against the max number of GPU texture units:
        if ( maxUnits > Registry::instance()->getCapabilities().getMaxGPUTextureUnits() )
        {
            maxUnits = Registry::instance()->getCapabilities().getMaxGPUTextureUnits();

            OE_WARN << LC
                << "Warning! You have exceeded the number of texture units available on your GPU ("
                << maxUnits << "). Consider using another compositing mode."
                << std::endl;
        }

        VirtualProgram* vp = static_cast<VirtualProgram*>( stateSet->getAttribute(osg::StateAttribute::PROGRAM) );
        if ( maxUnits > 0 )
        {
            // see if we have any blended layers:
            bool hasBlending = layout.containsSecondarySlots( maxUnits ); 

            vp->setShader( 
                "osgearth_vert_setupTexturing", 
                s_createTextureVertexShader(layout, hasBlending) );

            vp->setShader( 
                "osgearth_frag_applyTexturing",
                s_createTextureFragShaderFunction(layout, maxUnits, hasBlending, _lodTransitionTime ) );
        }
        else
        {
            vp->removeShader( "osgearth_frag_applyTexturing" );
            vp->removeShader( "osgearth_vert_setupTexturing" );
        }
    }

    else
    {
        // Forcably disable shaders
        stateSet->setAttributeAndModes( new osg::Program(), osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );

        // Validate against the maximum number of textures available in FFP mode.
        if ( maxUnits > Registry::instance()->getCapabilities().getMaxFFPTextureUnits() )
        {
            maxUnits = Registry::instance()->getCapabilities().getMaxFFPTextureUnits();
            OE_WARN << LC << 
                "Warning! You have exceeded the number of texture units available in fixed-function pipeline "
                "mode on your graphics hardware (" << maxUnits << "). Consider using another "
                "compositing mode." << std::endl;
        }

        // FFP multitexturing requires that we set up a series of TexCombine attributes:
        if (maxUnits == 1)
        {
            osg::TexEnv* texenv = new osg::TexEnv(osg::TexEnv::MODULATE);
            stateSet->setTextureAttributeAndModes(0, texenv, osg::StateAttribute::ON);
        }
        else if (maxUnits >= 2)
        {
            //Blend together the colors and accumulate the alpha values of textures 0 and 1 on unit 0
            {
                osg::TexEnvCombine* texenv = new osg::TexEnvCombine;
                texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
                texenv->setCombine_Alpha(osg::TexEnvCombine::ADD);

                texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+1);
                texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
                texenv->setSource0_Alpha(osg::TexEnvCombine::TEXTURE0+1);
                texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);

                texenv->setSource1_RGB(osg::TexEnvCombine::TEXTURE0+0);
                texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
                texenv->setSource1_Alpha(osg::TexEnvCombine::TEXTURE0+0);
                texenv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA);

                texenv->setSource2_RGB(osg::TexEnvCombine::TEXTURE0+1);
                texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA);

                stateSet->setTextureAttributeAndModes(0, texenv, osg::StateAttribute::ON);
            }


            //For textures 2 and beyond, blend them together with the previous
            //Add the alpha values of this unit and the previous unit
            for (int unit = 1; unit < maxUnits-1; ++unit)
            {
                osg::TexEnvCombine* texenv = new osg::TexEnvCombine;
                texenv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
                texenv->setCombine_Alpha(osg::TexEnvCombine::ADD);

                texenv->setSource0_RGB(osg::TexEnvCombine::TEXTURE0+unit+1);
                texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
                texenv->setSource0_Alpha(osg::TexEnvCombine::TEXTURE0+unit+1);
                texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);

                texenv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
                texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
                texenv->setSource1_Alpha(osg::TexEnvCombine::PREVIOUS);
                texenv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA);

                texenv->setSource2_RGB(osg::TexEnvCombine::TEXTURE0+unit+1);
                texenv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA);

                stateSet->setTextureAttributeAndModes(unit, texenv, osg::StateAttribute::ON);
            }

            //Modulate the colors to get proper lighting on the last unit
            //Keep the alpha results from the previous stage
            {
                osg::TexEnvCombine* texenv = new osg::TexEnvCombine;
                texenv->setCombine_RGB(osg::TexEnvCombine::MODULATE);
                texenv->setCombine_Alpha(osg::TexEnvCombine::REPLACE);

                texenv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
                texenv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
                texenv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS);
                texenv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);

                texenv->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
                texenv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
                stateSet->setTextureAttributeAndModes(maxUnits-1, texenv, osg::StateAttribute::ON);
            }
        }
    }
}
void
SplatTerrainEffect::onInstall(TerrainEngineNode* engine)
{
    if ( engine )
    {
        // Check that we have coverage data (required for now - later masking data will be an option)
        if ( !_coverage.valid() || !_coverage->hasLayer() )
        {
            OE_WARN << LC << "ILLEGAL: coverage data is required\n";
            return;
        }

        if ( !_surface.valid() )
        {
            OE_WARN << LC << "Note: no surface information available\n";
        }

        // First, create a surface splatting texture array for each biome region.
        if ( _coverage.valid() && _surface.valid() )
        {
            if ( createSplattingTextures(_coverage.get(), _surface.get(), _textureDefs) == false )
            {
                OE_WARN << LC << "Failed to create any valid splatting textures\n";
                return;
            }
            
            // First install a shared noise texture.
            if ( _gpuNoise == false )
            {
                osg::StateSet* terrainStateSet = engine->getOrCreateStateSet();
                if ( terrainStateSet->getUniform("oe_splat_noiseTex") == 0L )
                {
                    // reserve a texture unit:
                    if (engine->getResources()->reserveTextureImageUnit(_noiseTexUnit, "Splat Noise"))
                    {
                        NoiseTextureFactory noise;
                        terrainStateSet->setTextureAttribute( _noiseTexUnit, noise.create(256u, 4u) );
                        terrainStateSet->addUniform( new osg::Uniform("oe_splat_noiseTex", _noiseTexUnit) );
                    }
                }
            }

            // Set up surface splatting:
            if ( engine->getResources()->reserveTextureImageUnit(_splatTexUnit, "Splat Coverage Data") )
            {
                osg::StateSet* stateset;

                if ( _surface->getBiomeRegions().size() == 1 )
                    stateset = engine->getSurfaceStateSet();
                else
                    stateset = new osg::StateSet();

                // surface splatting texture array:
                _splatTexUniform = stateset->getOrCreateUniform( SPLAT_SAMPLER, osg::Uniform::SAMPLER_2D_ARRAY );
                _splatTexUniform->set( _splatTexUnit );
                stateset->setTextureAttribute( _splatTexUnit, _textureDefs[0]._texture.get() );

                // coverage code sampler:
                osg::ref_ptr<ImageLayer> coverageLayer;
                _coverage->lockLayer( coverageLayer );

                _coverageTexUniform = stateset->getOrCreateUniform( COVERAGE_SAMPLER, osg::Uniform::SAMPLER_2D );
                _coverageTexUniform->set( coverageLayer->shareImageUnit().get() );

                // control uniforms (TODO: simplify and deprecate unneeded uniforms)
                stateset->addUniform( _scaleOffsetUniform.get() );
                stateset->addUniform( _warpUniform.get() );
                stateset->addUniform( _blurUniform.get() );
                stateset->addUniform( _noiseScaleUniform.get() );
                stateset->addUniform( _useBilinearUniform.get() );

                stateset->addUniform(new osg::Uniform("oe_splat_detailRange",  1000000.0f));


                SplattingShaders splatting;

                splatting.define( "SPLAT_EDIT",        _editMode );
                splatting.define( "SPLAT_GPU_NOISE",   _gpuNoise );
                splatting.define( "OE_USE_NORMAL_MAP", engine->normalTexturesRequired() );

                splatting.replace( "$COVERAGE_TEXTURE_MATRIX", coverageLayer->shareTexMatUniformName().get() );
            
                VirtualProgram* vp = VirtualProgram::getOrCreate(stateset);
                splatting.load( vp, splatting.VertModel );
                splatting.load( vp, splatting.VertView );
                splatting.load( vp, splatting.Frag );
                splatting.load( vp, splatting.Util );

                // GPU noise is expensive, so only use it to tweak noise function values that you
                // can later bake into the noise texture generator.
                if ( _gpuNoise )
                {                
                    //osgEarth::replaceIn( fragmentShader, "#undef SPLAT_GPU_NOISE", "#define SPLAT_GPU_NOISE" );

                    // Use --uniform on the command line to tweak these values:
                    stateset->addUniform(new osg::Uniform("oe_splat_freq",   32.0f));
                    stateset->addUniform(new osg::Uniform("oe_splat_pers",    0.8f));
                    stateset->addUniform(new osg::Uniform("oe_splat_lac",     2.2f));
                    stateset->addUniform(new osg::Uniform("oe_splat_octaves", 8.0f));

                    // support shaders
                    std::string noiseShaderSource = ShaderLoader::load( splatting.Noise, splatting );
                    osg::Shader* noiseShader = new osg::Shader(osg::Shader::FRAGMENT, noiseShaderSource);
                    vp->setShader( "oe_splat_noiseshaders", noiseShader );
                }

                // TODO: disabled biome selection temporarily because the callback impl applies the splatting shader
                // to the land cover bin as well as the surface bin, which we do not want -- find another way
                if ( _surface->getBiomeRegions().size() == 1 )
                {
                    // install his biome's texture set:
                    stateset->setTextureAttribute(_splatTexUnit, _textureDefs[0]._texture.get());

                    // install this biome's sampling function. Use cloneOrCreate since each
                    // stateset needs a different shader set in its VP.
                    VirtualProgram* vp = VirtualProgram::cloneOrCreate( stateset );
                    osg::Shader* shader = new osg::Shader(osg::Shader::FRAGMENT, _textureDefs[0]._samplingFunction);
                    vp->setShader( "oe_splat_getRenderInfo", shader );
                }

                else
                {
                    OE_WARN << LC << "Multi-biome setup needs re-implementing (reminder)\n";

                    // install the cull callback that will select the appropriate
                    // state based on the position of the camera.
                    _biomeRegionSelector = new BiomeRegionSelector(
                        _surface->getBiomeRegions(),
                        _textureDefs,
                        stateset,
                        _splatTexUnit );

                    engine->addCullCallback( _biomeRegionSelector.get() );
                }
            }
        }
    }
}
Beispiel #9
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;
    }
}
Beispiel #10
0
void
DetailTexture::onInstall(TerrainEngineNode* engine)
{
    if ( engine )
    {
        if ( !_texture.valid() )
        {
            _texture = new osg::Texture2DArray();
            _texture->setTextureSize(1024, 1024, _textures.size());
            _texture->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT );
            _texture->setWrap( osg::Texture::WRAP_T, osg::Texture::REPEAT );
            _texture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
            _texture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
            _texture->setResizeNonPowerOfTwoHint( false );

            for(unsigned i=0; i<_textures.size(); ++i)
            {
                const TextureSource& ts = _textures[i];
                osg::ref_ptr<osg::Image> image = URI(ts._url).getImage(_dbOptions.get());
                if ( image->s() != 1024 || image->t() != 1024 )
                {
                    osg::ref_ptr<osg::Image> imageResized;
                    ImageUtils::resizeImage( image.get(), 1024, 1024, imageResized );
                    _texture->setImage( i, imageResized.get() );
                }
                else
                {
                    _texture->setImage( i, image.get() );
                }
            }
        }

        osg::StateSet* stateset = engine->getOrCreateStateSet();

        if ( engine->getTextureCompositor()->reserveTextureImageUnit(_unit) )
        {
            _samplerUniform = stateset->getOrCreateUniform( "oe_detail_tex", osg::Uniform::SAMPLER_2D_ARRAY );
            _samplerUniform->set( _unit );
            stateset->setTextureAttribute( _unit, _texture.get(), osg::StateAttribute::ON ); // don't use "..andModes"
        }

        if ( _maskLayer.valid() )
        {
            int unit = *_maskLayer->shareImageUnit();
            _maskUniform = stateset->getOrCreateUniform("oe_detail_mask", osg::Uniform::SAMPLER_2D);
            _maskUniform->set(unit);
            OE_NOTICE << LC << "Installed layer " << _maskLayer->getName() << " as texture mask on unit " << unit << std::endl;
        }
        else
        {
            exit(-1);
        }

        stateset->addUniform( _startLODUniform.get() );
        stateset->addUniform( _intensityUniform.get() );
        stateset->addUniform( _scaleUniform.get() );
        stateset->addUniform( _attenuationDistanceUniform.get() );

        std::string fs = generateFragmentShader( _textures.size(), _octaves.value() );
        VirtualProgram* vp = VirtualProgram::getOrCreate(stateset);
        vp->setFunction( "oe_detail_vertex",   vs, ShaderComp::LOCATION_VERTEX_VIEW );
        vp->setFunction( "oe_detail_fragment", fs, ShaderComp::LOCATION_FRAGMENT_COLORING );

        vp->setShader(
            "simplexNoise",
            new osg::Shader(osg::Shader::FRAGMENT, snoise) );
    }
}
Beispiel #11
0
void
SplatTerrainEffect::onInstall(TerrainEngineNode* engine)
{
    if ( engine && _ok )
    {
        if ( !_coverageLayer.valid() )
        {
            OE_WARN << LC << "No coverage layer set\n";
            return;
        }

        engine->requireElevationTextures();

        // install the splat texture array:
        if ( engine->getResources()->reserveTextureImageUnit(_splatTexUnit) )
        {
            osg::StateSet* stateset = new osg::StateSet();

            // splat sampler
            _splatTexUniform = stateset->getOrCreateUniform( SPLAT_SAMPLER, osg::Uniform::SAMPLER_2D_ARRAY );
            _splatTexUniform->set( _splatTexUnit );
            stateset->setTextureAttribute( _splatTexUnit, _textureDefs[0]._texture.get() );

            // coverage sampler
            _coverageTexUniform = stateset->getOrCreateUniform( COVERAGE_SAMPLER, osg::Uniform::SAMPLER_2D );
            _coverageTexUniform->set( _coverageLayer->shareImageUnit().get() );

            // control uniforms
            stateset->addUniform( _scaleOffsetUniform.get() );
            stateset->addUniform( _warpUniform.get() );
            stateset->addUniform( _blurUniform.get() );
            stateset->addUniform( _noiseScaleUniform.get() );
            stateset->addUniform( _useBilinearUniform.get() );

            stateset->addUniform(new osg::Uniform("oe_splat_detailRange",  1000000.0f));

            // Configure the vertex shader:
            std::string vertexShaderModel = ShaderLoader::load(_shaders.VertModel, _shaders);
            std::string vertexShaderView = ShaderLoader::load(_shaders.VertView, _shaders);

            osgEarth::replaceIn( vertexShaderView, "$COVERAGE_TEXMAT_UNIFORM", _coverageLayer->shareTexMatUniformName().get() );
            
            // Configure the fragment shader:
            std::string fragmentShader = ShaderLoader::load(_shaders.Frag, _shaders);

            if ( _editMode ) 
            {
                osgEarth::replaceIn( fragmentShader, "#undef SPLAT_EDIT", "#define SPLAT_EDIT" );
            }

            // are normal maps available?
            if ( engine->normalTexturesRequired() )
            {
                osgEarth::replaceIn( fragmentShader, "#undef OE_USE_NORMAL_MAP", "#define OE_USE_NORMAL_MAP" );
            }

            // GPU noise is expensive, so only use it to tweak noise function values that you
            // can later bake into the noise texture generator.
            if ( _gpuNoise )
            {                
                osgEarth::replaceIn( fragmentShader, "#undef SPLAT_GPU_NOISE", "#define SPLAT_GPU_NOISE" );

                // Use --uniform on the command line to tweak these values:
                stateset->addUniform(new osg::Uniform("oe_splat_freq",   32.0f));
                stateset->addUniform(new osg::Uniform("oe_splat_pers",    0.8f));
                stateset->addUniform(new osg::Uniform("oe_splat_lac",     2.2f));
                stateset->addUniform(new osg::Uniform("oe_splat_octaves", 8.0f));
            }
            else // use a noise texture (the default)
            {
                if (engine->getResources()->reserveTextureImageUnit(_noiseTexUnit))
                {
                    OE_INFO << LC << "Noise texture -> unit " << _noiseTexUnit << "\n";
                    _noiseTex = createNoiseTexture();
                    stateset->setTextureAttribute( _noiseTexUnit, _noiseTex.get() );
                    _noiseTexUniform = stateset->getOrCreateUniform( NOISE_SAMPLER, osg::Uniform::SAMPLER_2D );
                    _noiseTexUniform->set( _noiseTexUnit );
                }
            }

            // shader components
            VirtualProgram* vp = VirtualProgram::getOrCreate(stateset);
            vp->setFunction( "oe_splat_vertex_model", vertexShaderModel, ShaderComp::LOCATION_VERTEX_MODEL );
            vp->setFunction( "oe_splat_vertex_view",  vertexShaderView,  ShaderComp::LOCATION_VERTEX_VIEW );
            vp->setFunction( "oe_splat_fragment",     fragmentShader,    ShaderComp::LOCATION_FRAGMENT_COLORING, _renderOrder );

            if ( _gpuNoise )
            {
                // support shaders
                std::string noiseShaderSource = ShaderLoader::load(_shaders.Noise, _shaders);
                osg::Shader* noiseShader = new osg::Shader(osg::Shader::FRAGMENT, noiseShaderSource);
                vp->setShader( "oe_splat_noiseshaders", noiseShader );
            }

            // install the cull callback that will select the appropriate
            // state based on the position of the camera.
            _biomeSelector = new BiomeSelector(
                _biomes,
                _textureDefs,
                stateset,
                _splatTexUnit );

            engine->addCullCallback( _biomeSelector.get() );
        }
    }
}
void
LandCoverTerrainEffect::onInstall(TerrainEngineNode* engine)
{
    // First verify that the land cover definition is legal
    if ( !_landCover.valid() )
        return;

    if ( engine )
    {
        // install a noise texture if we haven't already.
        osg::StateSet* terrainStateSet = engine->getOrCreateStateSet();

        // check whether it's already installed by another extension:
        if ( terrainStateSet->getUniform("oe_splat_noiseTex") == 0L )
        {
            // reserve a texture unit:
            if (engine->getResources()->reserveTextureImageUnit(_noiseTexUnit, "Splat Noise"))
            {
                NoiseTextureFactory noise;
                terrainStateSet->setTextureAttribute( _noiseTexUnit, noise.create(256u, 4u) );
                terrainStateSet->addUniform( new osg::Uniform("oe_splat_noiseTex", _noiseTexUnit) );
            }
        }

        for(LandCoverLayers::const_iterator i = _landCover->getLayers().begin();
            i != _landCover->getLayers().end();
            ++i)
        {
            const LandCoverLayer* layer = i->get();
            if ( layer )
            {
                if ( !layer->getBiomes().empty() )
                {
                    osg::StateSet* stateset = engine->addLandCoverGroup( layer->getName(), layer->getLOD() );
                    if ( stateset )
                    {
                        // Install the land cover shaders on the state set
                        VirtualProgram* vp = VirtualProgram::getOrCreate(stateset);
                        LandCoverShaders shaders;
                        shaders.loadAll( vp, _dbo.get() );

                        // Generate the coverage acceptor shader
                        osg::Shader* covTest = layer->createPredicateShader( getCoverage() );
                        covTest->setType( osg::Shader::TESSCONTROL );
                        vp->setShader( covTest );

                        osg::ref_ptr<osg::Shader> layerShader = layer->createShader();
                        layerShader->setType( osg::Shader::GEOMETRY );
                        vp->setShader( layerShader );

                        OE_INFO << LC << "Adding land cover group: " << layer->getName() << " at LOD " << layer->getLOD() << "\n";

                        // Install the uniforms
                        stateset->addUniform( new osg::Uniform("oe_landcover_windFactor", layer->getWind()) );
                        stateset->addUniform( new osg::Uniform("oe_landcover_noise", 1.0f) );
                        stateset->addUniform( new osg::Uniform("oe_landcover_ao", 0.5f) );
                        stateset->addUniform( new osg::Uniform("oe_landcover_exposure", 1.0f) );
                    
                        stateset->addUniform( new osg::Uniform("oe_landcover_density",     layer->getDensity()) );
                        stateset->addUniform( new osg::Uniform("oe_landcover_fill",        layer->getFill()) );
                        stateset->addUniform( new osg::Uniform("oe_landcover_maxDistance", layer->getMaxDistance()) );

                        stateset->addUniform( new osg::Uniform("oe_landcover_brightness",  layer->getBrightness()) );
                        stateset->addUniform( new osg::Uniform("oe_landcover_contrast",    layer->getContrast()) );

                        stateset->addUniform( new osg::Uniform("oe_landcover_noise", 0.75f) );

                        int unit;
                        if ( engine->getResources()->reserveTextureImageUnit(unit, "LandCover") )
                        {
                            int s=-1, t=-1;

                            osg::Texture2DArray* tex = new osg::Texture2DArray();
                            
                            int arrayIndex = 0;
                            for(int b=0; b<layer->getBiomes().size(); ++b)
                            {
                                const LandCoverBiome* biome = layer->getBiomes().at(b);
                                
                                for(int i=0; i<biome->getBillboards().size(); ++i, ++arrayIndex)
                                {
                                    const LandCoverBillboard& bb = biome->getBillboards().at(i);

                                    osg::ref_ptr<osg::Image> im;

                                    if ( s < 0 )
                                    {
                                        s  = bb._image->s();
                                        t  = bb._image->t();
                                        im = bb._image.get();
                                        tex->setTextureSize(s, t, layer->getTotalNumBillboards());                              
                                    }
                                    else
                                    {
                                        if ( bb._image->s() != s || bb._image->t() != t )
                                        {
                                            ImageUtils::resizeImage( bb._image.get(), s, t, im );
                                        }
                                        else
                                        {
                                            im = bb._image.get();
                                        }
                                    }

                                    tex->setImage( arrayIndex, im.get() );
                                }
                            }
                                    
                            tex->setFilter(tex->MIN_FILTER, tex->NEAREST_MIPMAP_LINEAR);
                            tex->setFilter(tex->MAG_FILTER, tex->LINEAR);
                            tex->setWrap  (tex->WRAP_S, tex->CLAMP_TO_EDGE);
                            tex->setWrap  (tex->WRAP_T, tex->CLAMP_TO_EDGE);
                            tex->setUnRefImageDataAfterApply( true );
                            tex->setMaxAnisotropy( 4.0 );
                            tex->setResizeNonPowerOfTwoHint( false );

                            stateset->setTextureAttribute(unit, tex);
                            stateset->addUniform(new osg::Uniform("oe_landcover_texArray", unit) );
                        }
                        else
                        {
                            OE_WARN << LC << "Terrain engine failed to allocate a texture image unit for a land cover group\n";
                        }
                    }
                    else
                    {
                        OE_WARN << LC << "Terrain engine failed to return a stateset for a land cover group\n";
                    }
                }
                else
                {
                    OE_WARN << LC << "ILLEGAL: land cover layer with no biomes defined\n";
                }
            }
            else
            {
                OE_WARN << LC << "ILLEGAL: empty layer found in land cover layer list\n";
            }
        }
    }
}