Example #1
0
VirtualProgram* 
RTTPicker::createRTTProgram()
{    
    VirtualProgram* vp = new VirtualProgram();
    vp->setName( "osgEarth::RTTPicker" );

    // Install RTT picker shaders:
    ShaderPackage pickShaders;
    pickShaders.add( "RTTPicker.vert.glsl", pickVertexEncode );
    pickShaders.add( "RTTPicker.frag.glsl", pickFragment );
    pickShaders.loadAll( vp );

    // Install shaders and bindings from the ObjectIndex:
    Registry::objectIndex()->loadShaders( vp );

    return vp;
}
bool
BillboardExtension::connect(MapNode* mapNode)
{
    if ( !mapNode )
    {
        OE_WARN << LC << "Illegal: MapNode cannot be null." << std::endl;
        return false;
    }

    OE_INFO << LC << "Connecting to MapNode.\n";

    if ( !_options.imageURI().isSet() )
    {
        OE_WARN << LC << "Illegal: image URI is required" << std::endl;
        return false;
    }

    if ( !_options.featureOptions().isSet() )
    {
        OE_WARN << LC << "Illegal: feature source is required" << std::endl;
        return false;
    }
    
    _features = FeatureSourceFactory::create( _options.featureOptions().value() );
    if ( !_features.valid() )
    {
        OE_WARN << LC << "Illegal: no valid feature source provided" << std::endl;
        return false;
    }

    //if ( _features->getGeometryType() != osgEarth::Symbology::Geometry::TYPE_POINTSET )
    //{
    //    OE_WARN << LC << "Illegal: only points currently supported" << std::endl;
    //    return false;
    //}

    _features->initialize( _dbOptions );

    osg::Vec3dArray* verts;
    if ( _features->getFeatureProfile() )
    {
        verts = new osg::Vec3dArray();
        
        OE_NOTICE << "Reading features...\n";
        osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor();
        while ( cursor.valid() && cursor->hasMore() )
        {
            Feature* f = cursor->nextFeature();
            if ( f && f->getGeometry() )
            {
                if ( f->getGeometry()->getComponentType() == Geometry::TYPE_POLYGON )
                {
                    FilterContext cx;
                    cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) );

                    ScatterFilter scatter;
                    scatter.setDensity( _options.density().get() );
                    scatter.setRandom( true );
                    FeatureList featureList;
                    featureList.push_back(f);
                    scatter.push( featureList, cx );
                }

                // Init a filter to tranform feature in desired SRS 
                if (!mapNode->getMapSRS()->isEquivalentTo(_features->getFeatureProfile()->getSRS()))
                {
                    FilterContext cx;
                    cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) );

                    TransformFilter xform( mapNode->getMapSRS() );
                    FeatureList featureList;
                    featureList.push_back(f);
                    cx = xform.push(featureList, cx);
                }

                GeometryIterator iter(f->getGeometry());
                while(iter.hasMore()) {
                    const Geometry* geom = iter.next();
                    osg::ref_ptr<osg::Vec3dArray> fVerts = geom->createVec3dArray();
                    verts->insert(verts->end(), fVerts->begin(), fVerts->end());
                }
            }
        }
    }
    else
    {
        OE_WARN << LC << "Illegal: feature source has no SRS" << std::endl;
        return false;
    }


    if ( verts && verts->size() > 0 )
    {
        OE_NOTICE << LC << "Read " << verts->size() << " points.\n";

        //localize all the verts
        GeoPoint centroid;
        _features->getFeatureProfile()->getExtent().getCentroid(centroid);
        centroid = centroid.transform(mapNode->getMapSRS());

        OE_NOTICE << "Centroid = " << centroid.x() << ", " << centroid.y() << "\n";

        osg::Matrixd l2w, w2l;
        centroid.createLocalToWorld(l2w);
        w2l.invert(l2w);

        osg::MatrixTransform* mt = new osg::MatrixTransform;
        mt->setMatrix(l2w);

        OE_NOTICE << "Clamping elevations...\n";
        osgEarth::ElevationQuery eq(mapNode->getMap());
        eq.setFallBackOnNoData( true );
        eq.getElevations(verts->asVector(), mapNode->getMapSRS(), true, 0.005);
        
        OE_NOTICE << "Building geometry...\n";
        osg::Vec3Array* normals = new osg::Vec3Array(verts->size());

        osg::Vec4Array* colors = new osg::Vec4Array(verts->size());
        Random rng;

        for (int i=0; i < verts->size(); i++)
        {
            GeoPoint vert(mapNode->getMapSRS(), (*verts)[i], osgEarth::ALTMODE_ABSOLUTE);

            osg::Vec3d world;
            vert.toWorld(world);
            (*verts)[i] = world * w2l;

            osg::Vec3 normal = world;
            normal.normalize();
            (*normals)[i] = osg::Matrix::transform3x3(normal, w2l);

            double n = rng.next();
            (*colors)[i].set( n, n, n, 1 );
        }

        //create geom and primitive sets
        osg::Geometry* geometry = new osg::Geometry();
        geometry->setVertexArray( verts );
        geometry->setNormalArray( normals );
        geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
        geometry->setColorArray(colors);
        geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );

        geometry->addPrimitiveSet( new osg::DrawArrays( GL_POINTS, 0, verts->size() ) );

        //create image and texture to render to
        osg::Texture2D* tex = new osg::Texture2D(_options.imageURI()->getImage(_dbOptions));
        tex->setResizeNonPowerOfTwoHint(false);
        tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
        tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
        tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
        tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);

        geometry->setName("BillboardPoints");

        osg::Geode* geode = new osg::Geode;
        geode->addDrawable(geometry);

        //osg::ref_ptr<StateSetCache> cache = new StateSetCache();
        //Registry::shaderGenerator().run(geode, cache.get());

        //set the texture related uniforms
        osg::StateSet* geode_ss = geode->getOrCreateStateSet();
        geode_ss->setTextureAttributeAndModes( 2, tex, 1 );
        geode_ss->getOrCreateUniform("billboard_tex", osg::Uniform::SAMPLER_2D)->set( 2 );

        float bbWidth = (float)tex->getImage()->s() / 2.0f;
        float bbHeight = (float)tex->getImage()->t();
        float aspect = (float)tex->getImage()->s() / (float)tex->getImage()->t();
        if (_options.height().isSet())
        {
            bbHeight = _options.height().get();
            if (!_options.width().isSet())
            {
                bbWidth = bbHeight * aspect / 2.0f;
            }
        }
        if (_options.width().isSet())
        {
            bbWidth = _options.width().get() / 2.0f;
            if (!_options.height().isSet())
            {
                bbHeight = _options.width().get() / aspect;
            }
        }

        geode_ss->getOrCreateUniform("billboard_width", osg::Uniform::FLOAT)->set( bbWidth );
        geode_ss->getOrCreateUniform("billboard_height", osg::Uniform::FLOAT)->set( bbHeight );
        geode_ss->setMode(GL_BLEND, osg::StateAttribute::ON);

        //for now just using an osg::Program
        //TODO: need to add GeometryShader support to the shader comp setup
        VirtualProgram* vp = VirtualProgram::getOrCreate(geode_ss);
        vp->setName( "osgEarth Billboard Extension" );

        ShaderPackage shaders;
        shaders.add( "Billboard geometry shader", billboardGeomShader );
        shaders.add( "Billboard fragment shader", billboardFragShader );
        shaders.loadAll( vp );

        geode_ss->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
        geode->setCullingActive(false);

        mt->addChild(geode);
        mapNode->getModelLayerGroup()->addChild(mt);

        return true;
    }

    return false;
}
void
LayerShader::install(Layer* layer, TerrainResources* res)
{
    if (!layer || !res)
        return;

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

    VirtualProgram* vp = VirtualProgram::getOrCreate(stateset);
    ShaderPackage package;
    package.add("", _options.code());
    package.loadAll(vp, layer->getReadOptions());

    for (int i = 0; i < _options.samplers().size(); ++i)
    {
        const ShaderOptions::Sampler& sampler = _options.samplers()[i];
        if (!sampler._name.empty())
        {
            _reservations.push_back(TextureImageUnitReservation());
            TextureImageUnitReservation& reservation = _reservations.back();

            if (sampler._uris.size() == 1) // Texture2D
            {
                if (res->reserveTextureImageUnitForLayer(reservation, layer, "User shader sampler"))
                {
                    osg::Image* image = sampler._uris[0].getImage(layer->getReadOptions());
                    if (image)
                    {
                        osg::Texture2D* tex = new osg::Texture2D(image);
                        tex->setFilter(tex->MIN_FILTER, tex->NEAREST_MIPMAP_LINEAR);
                        tex->setFilter(tex->MAG_FILTER, tex->LINEAR);
                        tex->setWrap(tex->WRAP_S, tex->REPEAT);
                        tex->setWrap(tex->WRAP_T, tex->REPEAT);
                        tex->setUnRefImageDataAfterApply(true);
                        tex->setMaxAnisotropy(4.0);
                        tex->setResizeNonPowerOfTwoHint(false);

                        stateset->setTextureAttribute(reservation.unit(), tex);
                        stateset->addUniform(new osg::Uniform(sampler._name.c_str(), reservation.unit()));
                    }
                }
                else
                {
                    OE_WARN << LC << "Failed to allocate a texture image unit for this terrain shader sampler!\n";
                }
            }

            else if (sampler._uris.size() > 1) // Texture2DArray
            {
                if (res->reserveTextureImageUnitForLayer(reservation, layer, "User shader sampler array"))
                {
                    int sizeX = 0, sizeY = 0;
                    osg::Texture2DArray* tex = new osg::Texture2DArray();
                    tex->setTextureSize(512, 512, sampler._uris.size());
                    tex->setTextureDepth(sampler._uris.size());

                    for (int j = 0; j < sampler._uris.size(); ++j)
                    {
                        const URI& uri = sampler._uris[j];

                        osg::ref_ptr<osg::Image> image = uri.getImage(layer->getReadOptions());
                        if (image)
                        {
                            OE_INFO << LC << "   Added image from \"" << uri.full() << "\"\n";
                            tex->setImage(i, image);
                            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->setResizeNonPowerOfTwoHint(false);

                            stateset->setTextureAttribute(reservation.unit(), tex);
                            stateset->addUniform(new osg::Uniform(sampler._name.c_str(), reservation.unit()));

                            if (sizeX == 0)
                            {
                                sizeX = image->s();
                                sizeY = image->t();
                                tex->setTextureSize(sizeX, sizeY, sampler._uris.size());
                            }
                        }
                    }
                }
                else
                {
                    OE_WARN << LC << "Failed to allocate a texture image unit for this terrain shader sampler!\n";
                }
            }
        }
    }

    for (int i = 0; i < _options.uniforms().size(); ++i)
    {
        const ShaderOptions::Uniform& uniform = _options.uniforms()[i];
        if (!uniform._name.empty() && uniform._value.isSet())
        {
            osg::Uniform* u = new osg::Uniform(uniform._name.c_str(), (float)uniform._value.get());
            stateset->addUniform(u);
        }
    }
}