Exemple #1
0
void
ShaderGenerator::run(osg::Node* graph, StateSetCache* cache)
{
    if ( graph )
    {
        _texImageUnits.clear();

        // generate shaders:
        graph->accept( *this );

        // perform GL state sharing
        if ( cache )
            cache->optimize( graph );

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

        // install a blank VP at the top as the default.
        VirtualProgram* vp = VirtualProgram::get(stateset);
        if ( !vp )
        {
            vp = VirtualProgram::getOrCreate(stateset);
            vp->setInheritShaders( true );
            vp->setName( _name );
        }

        // apply a uniform for each sampler binding we found.
        for(std::set<int>::iterator i = _texImageUnits.begin(); i != _texImageUnits.end(); ++i)
        {
            std::string name = Stringify() << SAMPLER << *i;
            stateset->addUniform( new osg::Uniform(name.c_str(), *i) );
        }
        _texImageUnits.clear();
    }
}
void
ShaderGenerator::run(osg::Node*         graph,
                     const std::string& vpName, 
                     StateSetCache*     cache)
{
    if ( graph )
    {
        // generate shaders:
        graph->accept( *this );

        // perform GL state sharing
        optimizeStateSharing( graph, cache );

        osg::StateSet* stateset = cloneOrCreateStateSet(graph);

        // install a blank VP at the top as the default.
        VirtualProgram* vp = VirtualProgram::get(stateset);
        if ( !vp )
        {
            vp = VirtualProgram::getOrCreate(stateset);
            vp->setInheritShaders( true );
            vp->setName( vpName );
        }
    }
}
Exemple #3
0
VirtualProgram*
VirtualProgram::cloneOrCreate(const osg::StateSet* src, osg::StateSet* dest)
{
    if ( !dest )
        return 0L;

    const VirtualProgram* vp = 0L;

    if ( src )
    {
        vp = get( src );
    }

    if ( !vp )
    {
        return getOrCreate( dest );
    }

    else
    {
        VirtualProgram* cloneVP = osg::clone( vp, osg::CopyOp::DEEP_COPY_ALL );
        cloneVP->setInheritShaders(true);
        dest->setAttributeAndModes(cloneVP, osg::StateAttribute::ON);
        return cloneVP;
    }
}
TileRasterizer::TileRasterizer() :
osg::Camera()
{
    // active an update traversal.
    setNumChildrenRequiringUpdateTraversal(1);
    setCullingActive(false);

    // set up the RTT camera.
    setClearColor(osg::Vec4(0,0,0,0));
    setClearMask(GL_COLOR_BUFFER_BIT);
    setReferenceFrame(ABSOLUTE_RF);
    //setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
    setRenderOrder(PRE_RENDER);
    setRenderTargetImplementation(FRAME_BUFFER_OBJECT);
    setImplicitBufferAttachmentMask(0, 0);
    setSmallFeatureCullingPixelSize(0.0f);
    setViewMatrix(osg::Matrix::identity());

    osg::StateSet* ss = getOrCreateStateSet();

    ss->setMode(GL_BLEND, 1);
    ss->setMode(GL_CULL_FACE, 0);
    GLUtils::setLighting(ss, 0);
    
    this->setPreDrawCallback(new PreDrawRouter<TileRasterizer>(this));
    this->setPostDrawCallback(new PostDrawRouter<TileRasterizer>(this));

#if 0 // works in OE, not in VRV :(
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits();
    traits->sharedContext = 0L;
    traits->doubleBuffer = false;
    traits->x = 0, traits->y = 0, traits->width = 256, traits->height = 256;
    traits->format = GL_RGBA;
    traits->red = 8;
    traits->green = 8;
    traits->blue = 8;
    traits->alpha = 8;
    traits->depth = 0;
    osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits);
    setGraphicsContext(gc);
#endif
    setDrawBuffer(GL_FRONT);
    setReadBuffer(GL_FRONT);

    VirtualProgram* vp = VirtualProgram::getOrCreate(ss);
    vp->setInheritShaders(false);

    // Someday we might need this to undistort rasterizer cells. We'll see
#if 0
    vp->setFunction("oe_rasterizer_clip", distort, ShaderComp::LOCATION_VERTEX_CLIP);
    _distortionU = new osg::Uniform("oe_rasterizer_f", 1.0f);
    ss->addUniform(_distortionU.get());
#endif
}
VirtualProgram* 
VirtualProgram::getOrCreate(osg::StateSet* stateset)
{
    if ( !stateset )
        return 0L;

    VirtualProgram* vp = dynamic_cast<VirtualProgram*>( stateset->getAttribute(SA_TYPE) );
    if ( !vp )
    {
        vp = new VirtualProgram();
        vp->setInheritShaders(true);
        stateset->setAttributeAndModes( vp, osg::StateAttribute::ON );
    }
    return vp;
}
void
DrapingTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params)
{
    // create the projected texture:
    osg::Texture2D* projTexture = new osg::Texture2D();
    projTexture->setTextureSize( *_textureSize, *_textureSize );
    projTexture->setInternalFormat( GL_RGBA );
    projTexture->setSourceFormat( GL_RGBA );
    projTexture->setSourceType( GL_UNSIGNED_BYTE );
    projTexture->setFilter( osg::Texture::MIN_FILTER, _mipmapping? osg::Texture::LINEAR_MIPMAP_LINEAR: osg::Texture::LINEAR );
    projTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
    projTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER );
    projTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER );
    //projTexture->setWrap( osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE );
    projTexture->setBorderColor( osg::Vec4(0,0,0,0) );

    // set up the RTT camera:
    params._rttCamera = new osg::Camera();
    params._rttCamera->setClearColor( osg::Vec4f(0,0,0,0) );
    // this ref frame causes the RTT to inherit its viewpoint from above (in order to properly
    // process PagedLOD's etc. -- it doesn't affect the perspective of the RTT camera though)
    params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT );
    params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize );
    params._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
    params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER );
    params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
    params._rttCamera->attach( osg::Camera::COLOR_BUFFER, projTexture, 0, 0, _mipmapping );

    if ( _attachStencil )
    {
        // try a depth-packed buffer. failing that, try a normal one.. if the FBO doesn't support
        // that (which is doesn't on some GPUs like Intel), it will automatically fall back on 
        // a PBUFFER_RTT impl
        if ( Registry::capabilities().supportsDepthPackedStencilBuffer() )
        {
#ifdef OSG_GLES2_AVAILABLE 
            params._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH24_STENCIL8_EXT );
#else
            params._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH_STENCIL_EXT );
#endif
        }
        else
        {
            params._rttCamera->attach( osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX );
        }

        params._rttCamera->setClearStencil( 0 );
        params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    }
    else
    {
        params._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    }

    // set up a StateSet for the RTT camera.
    osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet();

    // lighting is off. We don't want draped items to be lit.
    rttStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );

    // install a new default shader program that replaces anything from above.
    if ( _useShaders )
    {
        VirtualProgram* vp = VirtualProgram::getOrCreate(rttStateSet);
        vp->setName( "DrapingTechnique RTT" );
        vp->setInheritShaders( false );
        //rttStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON );
    }
    
    // active blending within the RTT camera's FBO
    if ( _rttBlending )
    {
        //Setup a separate blend function for the alpha components and the RGB components.  
        //Because the destination alpha is initialized to 0 instead of 1
        osg::BlendFunc* blendFunc = 0;        
        if (Registry::capabilities().supportsGLSL(1.4f))
        {
            //Blend Func Separate is only available on OpenGL 1.4 and above
            blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        }
        else
        {
            blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        }

        rttStateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
    }
    else
    {
        rttStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
    }

    // attach the overlay group to the camera. 
    // TODO: we should probably lock this since other cull traversals might be accessing the group
    //       while we are changing its children.
    params._rttCamera->addChild( params._group );

    // overlay geometry is rendered with no depth testing, and in the order it's found in the
    // scene graph... until further notice.
    rttStateSet->setMode(GL_DEPTH_TEST, 0);
    rttStateSet->setBinName( "TraversalOrderBin" );

    // add to the terrain stateset, i.e. the stateset that the OverlayDecorator will
    // apply to the terrain before cull-traversing it. This will activate the projective
    // texturing on the terrain.
    params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, projTexture, osg::StateAttribute::ON );

    // fire up the local per-view data:
    LocalPerViewData* local = new LocalPerViewData();
    params._techniqueData = local;
    
    if ( _useShaders )
    {            
        // GPU path

        VirtualProgram* vp = VirtualProgram::getOrCreate(params._terrainStateSet);
        vp->setName( "DrapingTechnique terrain shaders");
        //params._terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON );

        // sampler for projected texture:
        params._terrainStateSet->getOrCreateUniform(
            "oe_overlay_tex", osg::Uniform::SAMPLER_2D )->set( *_textureUnit );

        // the texture projection matrix uniform.
        local->_texGenUniform = params._terrainStateSet->getOrCreateUniform(
            "oe_overlay_texmatrix", osg::Uniform::FLOAT_MAT4 );

        // vertex shader - subgraph
        std::string vs =
            "#version " GLSL_VERSION_STR "\n"
            GLSL_DEFAULT_PRECISION_FLOAT "\n"
            "uniform mat4 oe_overlay_texmatrix; \n"
            "varying vec4 oe_overlay_texcoord; \n"

            "void oe_overlay_vertex(inout vec4 VertexVIEW) \n"
            "{ \n"
            "    oe_overlay_texcoord = oe_overlay_texmatrix * VertexVIEW; \n"
            "} \n";

        vp->setFunction( "oe_overlay_vertex", vs, ShaderComp::LOCATION_VERTEX_VIEW );

        // fragment shader - subgraph
        std::string fs =
            "#version " GLSL_VERSION_STR "\n"
            GLSL_DEFAULT_PRECISION_FLOAT "\n"
            "uniform sampler2D oe_overlay_tex; \n"
            "varying vec4      oe_overlay_texcoord; \n"

            "void oe_overlay_fragment( inout vec4 color ) \n"
            "{ \n"
            "    vec4 texel = texture2DProj(oe_overlay_tex, oe_overlay_texcoord); \n"
            "    color = vec4( mix( color.rgb, texel.rgb, texel.a ), color.a); \n"
            "} \n";

        vp->setFunction( "oe_overlay_fragment", fs, ShaderComp::LOCATION_FRAGMENT_COLORING );
    }
    else
    {
        // FFP path
        local->_texGen = new osg::TexGen();
        local->_texGen->setMode( osg::TexGen::EYE_LINEAR );
        params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, local->_texGen.get(), 1 );

        osg::TexEnv* env = new osg::TexEnv();
        env->setMode( osg::TexEnv::DECAL );
        params._terrainStateSet->setTextureAttributeAndModes( *_textureUnit, env, 1 );
    }
}
    /**
     * Creates a complete set of positioned label nodes from a feature list.
     */
    osg::Node* createNode(
        const FeatureList&   input,
        const Style&         style,
        const FilterContext& context )
    {
        if ( style.get<TextSymbol>() == 0L && style.get<IconSymbol>() == 0L )
            return 0L;

        // copy the style so we can (potentially) modify the text symbol.
        Style styleCopy = style;
        TextSymbol* text = styleCopy.get<TextSymbol>();
        IconSymbol* icon = styleCopy.get<IconSymbol>();

        osg::Group* group = new osg::Group();
        
        StringExpression  textContentExpr ( text ? *text->content()  : StringExpression() );
        NumericExpression textPriorityExpr( text ? *text->priority() : NumericExpression() );
        NumericExpression textSizeExpr    ( text ? *text->size()     : NumericExpression() );
        StringExpression  iconUrlExpr     ( icon ? *icon->url()      : StringExpression() );
        NumericExpression iconScaleExpr   ( icon ? *icon->scale()    : NumericExpression() );
        NumericExpression iconHeadingExpr ( icon ? *icon->heading()  : NumericExpression() );

        for( FeatureList::const_iterator i = input.begin(); i != input.end(); ++i )
        {
            const Feature* feature = i->get();
            if ( !feature )
                continue;

            const Geometry* geom = feature->getGeometry();
            if ( !geom )
                continue;

            Style tempStyle = styleCopy;

            // evaluate expressions into literals.
            // TODO: Later we could replace this with a generate "expression evaluator" type
            // that we could pass to PlaceNode in the DB options. -gw

            if ( text )
            {
                if ( text->content().isSet() )
                    tempStyle.get<TextSymbol>()->content()->setLiteral( feature->eval( textContentExpr, &context ) );

                if ( text->size().isSet() )
                    tempStyle.get<TextSymbol>()->size()->setLiteral( feature->eval(textSizeExpr, &context) );
            }

            if ( icon )
            {
                if ( icon->url().isSet() )
                    tempStyle.get<IconSymbol>()->url()->setLiteral( feature->eval(iconUrlExpr, &context) );

                if ( icon->scale().isSet() )
                    tempStyle.get<IconSymbol>()->scale()->setLiteral( feature->eval(iconScaleExpr, &context) );

                if ( icon->heading().isSet() )
                    tempStyle.get<IconSymbol>()->heading()->setLiteral( feature->eval(iconHeadingExpr, &context) );
            }
            
            osg::Node* node = makePlaceNode(
                context,
                feature,
                tempStyle,
                textPriorityExpr);

            if ( node )
            {
                if ( context.featureIndex() )
                {
                    context.featureIndex()->tagNode(node, const_cast<Feature*>(feature));
                }

                group->addChild( node );
            }
        }

        VirtualProgram* vp = VirtualProgram::getOrCreate(group->getOrCreateStateSet());
        vp->setInheritShaders( false );

        return group;
    }
void
ClampingTechnique::setUpCamera(OverlayDecorator::TechRTTParams& params)
{
    // To store technique-specific per-view info:
    LocalPerViewData* local = new LocalPerViewData();
    params._techniqueData = local;

    // create the projected texture:
    local->_rttTexture = new osg::Texture2D();
    local->_rttTexture->setTextureSize( *_textureSize, *_textureSize );
    local->_rttTexture->setInternalFormat( GL_DEPTH_COMPONENT );
    local->_rttTexture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::NEAREST );
    local->_rttTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );

    // this is important. geometry that is outside the depth texture will clamp to the
    // closest edge value in the texture -- this is good when you are rendering a 
    // primitive that has one or more of its verts off-screen.
    local->_rttTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE );
    local->_rttTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE );
    //local->_rttTexture->setBorderColor( osg::Vec4(0,0,0,1) );

    // set up the RTT camera:
    params._rttCamera = new osg::Camera();
    params._rttCamera->setName("GPU Clamping");
    params._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT );
    params._rttCamera->setClearDepth( 1.0 );
    params._rttCamera->setClearMask( GL_DEPTH_BUFFER_BIT );
    params._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
    params._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize );
    params._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER );
    params._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
    params._rttCamera->setImplicitBufferAttachmentMask(0, 0);
    params._rttCamera->attach( osg::Camera::DEPTH_BUFFER, local->_rttTexture.get() );

#ifdef DUMP_RTT_IMAGE
    local->_rttDebugImage = new osg::Image();
    local->_rttDebugImage->allocateImage(4096, 4096, 1, GL_RGB, GL_UNSIGNED_BYTE);
    memset( (void*)local->_rttDebugImage->getDataPointer(), 0xff, local->_rttDebugImage->getTotalSizeInBytes() );
    params._rttCamera->attach( osg::Camera::COLOR_BUFFER, local->_rttDebugImage.get() );
    params._rttCamera->setFinalDrawCallback( new DumpTex(local->_rttDebugImage.get()) );
#endif

#ifdef TIME_RTT_CAMERA
    params._rttCamera->setInitialDrawCallback( new RttIn() );
    params._rttCamera->setFinalDrawCallback( new RttOut() );
#endif

    // set up a StateSet for the RTT camera.
    osg::StateSet* rttStateSet = params._rttCamera->getOrCreateStateSet();

    rttStateSet->setMode(
        GL_BLEND, 
        osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);

    // prevents wireframe mode in the depth camera.
    rttStateSet->setAttributeAndModes(
        new osg::PolygonMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL ),
        osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );

    // install a VP on the stateset that cancels out any higher-up VP code.
    // This will prevent things like VPs on the main camera (e.g., log depth buffer)
    // from interfering with the depth camera
    VirtualProgram* rttVP = VirtualProgram::getOrCreate(rttStateSet);
    rttVP->setInheritShaders(false);
    
    // attach the terrain to the camera.
    // todo: should probably protect this with a mutex.....
    params._rttCamera->addChild( _engine ); // the terrain itself.

    // assemble the overlay graph stateset.
    local->_groupStateSet = new osg::StateSet();

    // Required for now, otherwise GPU-clamped geometry will jitter sometimes.
    // TODO: figure out why and fix it. This is a workaround for now.
    local->_groupStateSet->setDataVariance( osg::Object::DYNAMIC );

    local->_groupStateSet->setTextureAttributeAndModes( 
        _textureUnit, 
        local->_rttTexture.get(), 
        osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );

    // set up depth test/write parameters for the overlay geometry:
    local->_groupStateSet->setAttributeAndModes(
        new osg::Depth( osg::Depth::LEQUAL, 0.0, 1.0, true ),
        osg::StateAttribute::ON );

    local->_groupStateSet->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );

    // uniform for the horizon distance (== max clamping distance)
    local->_horizonDistance2Uniform = local->_groupStateSet->getOrCreateUniform(
        "oe_clamp_horizonDistance2",
        osg::Uniform::FLOAT );

    // sampler for depth map texture:
    local->_groupStateSet->getOrCreateUniform(
        "oe_clamp_depthTex", 
        osg::Uniform::SAMPLER_2D )->set( _textureUnit );

    // matrix that transforms a vert from EYE coords to the depth camera's CLIP coord.
    local->_camViewToDepthClipUniform = local->_groupStateSet->getOrCreateUniform( 
        "oe_clamp_cameraView2depthClip", 
        osg::Uniform::FLOAT_MAT4 );

#ifdef SUPPORT_Z

    // matrix that transforms a vert from depth clip coords to depth view coords.
    local->_depthClipToDepthViewUniform = local->_groupStateSet->getOrCreateUniform(
        "oe_clamp_depthClip2depthView",
        osg::Uniform::FLOAT_MAT4 );

    // matrix that transforms a vert from depth view coords to camera view coords.
    local->_depthViewToCamViewUniform = local->_groupStateSet->getOrCreateUniform(
        "oe_clamp_depthView2cameraView",
        osg::Uniform::FLOAT_MAT4 );

#else

    // matrix that transforms a vert from depth-cam CLIP coords to EYE coords.
    local->_depthClipToCamViewUniform = local->_groupStateSet->getOrCreateUniform( 
        "oe_clamp_depthClip2cameraView", 
        osg::Uniform::FLOAT_MAT4 );

#endif

    // default value for altitude offset; can be overriden by geometry.
    local->_groupStateSet->addUniform( new osg::Uniform(Clamping::AltitudeOffsetUniformName, 0.0f) );

    // make the shader that will do clamping and depth offsetting.
    VirtualProgram* vp = VirtualProgram::getOrCreate(local->_groupStateSet.get());
    vp->setName( "GPUClamping" );

    // Bind clamping attribute location, and a default uniform indicating whether
    // they are available (default is false).
    vp->addBindAttribLocation( Clamping::AnchorAttrName, Clamping::AnchorAttrLocation );
    local->_groupStateSet->addUniform( new osg::Uniform(Clamping::HasAttrsUniformName, false) );

    // Bind clamping heights location.
    vp->addBindAttribLocation( Clamping::HeightsAttrName, Clamping::HeightsAttrLocation );

    osgEarth::Shaders pkg;
    pkg.load(vp, pkg.GPUClampingVertex);
    pkg.load(vp, pkg.GPUClampingFragment);
}
void
OverlayDecorator::initializePerViewData( PerViewData& pvd )
{
    if ( !_textureUnit.isSet() || !_overlayGraph.valid() )
        return;

    // create the projected texture:
    osg::Texture2D* projTexture = new osg::Texture2D();
    projTexture->setTextureSize( *_textureSize, *_textureSize );
    projTexture->setInternalFormat( GL_RGBA );
    projTexture->setSourceFormat( GL_RGBA );
    projTexture->setSourceType( GL_UNSIGNED_BYTE );
    projTexture->setFilter( osg::Texture::MIN_FILTER, _mipmapping? osg::Texture::LINEAR_MIPMAP_LINEAR: osg::Texture::LINEAR );
    projTexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
    projTexture->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); //CLAMP_TO_BORDER );
    projTexture->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE );
    projTexture->setWrap( osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE );
    projTexture->setBorderColor( osg::Vec4(0,0,0,0) );

    // set up the RTT camera:
    pvd._rttCamera = new osg::Camera();
    pvd._rttCamera->setClearColor( osg::Vec4f(0,0,0,0) );
    pvd._rttCamera->setClearStencil( 0 );
    pvd._rttCamera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    // this ref frame causes the RTT to inherit its viewpoint from above (in order to properly
    // process PagedLOD's etc. -- it doesn't affect the perspective of the RTT camera though)
    pvd._rttCamera->setReferenceFrame( osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT );
    pvd._rttCamera->setViewport( 0, 0, *_textureSize, *_textureSize );
    pvd._rttCamera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
    pvd._rttCamera->setRenderOrder( osg::Camera::PRE_RENDER );
    pvd._rttCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );

    pvd._rttCamera->attach( osg::Camera::COLOR_BUFFER, projTexture, 0, 0, _mipmapping );

    if (_attachStencil) {
        // try a depth-packed buffer. failing that, try a normal one.. if the FBO doesn't support
        // that (which is doesn't on some GPUs like Intel), it will automatically fall back on 
        // a PBUFFER_RTT impl
        if ( Registry::instance()->getCapabilities().supportsDepthPackedStencilBuffer() )
        {
#ifdef OSG_GLES2_AVAILABLE 
            pvd._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH24_STENCIL8_EXT );
#else
            pvd._rttCamera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH_STENCIL_EXT );
#endif
        }
        else
        {
            pvd._rttCamera->attach( osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX );
        }
    }

    osg::StateSet* rttStateSet = pvd._rttCamera->getOrCreateStateSet();

    rttStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );

    // install a new default shader program that replaces anything from above.
    if ( _useShaders )
    {
        VirtualProgram* vp = new VirtualProgram();
        vp->setName( "overlay rtt" );
        vp->installDefaultColoringAndLightingShaders();
        vp->setInheritShaders( false );
        rttStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON );
    }
    
    if ( _rttBlending )
    {
        //Setup a separate blend function for the alpha components and the RGB components.  
        //Because the destination alpha is initialized to 0 instead of 1
        osg::BlendFunc* blendFunc = 0;        
        if (Registry::instance()->getCapabilities().supportsGLSL(1.4f))
        {
            //Blend Func Separate is only available on OpenGL 1.4 and above
            blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        }
        else
        {
            blendFunc = new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        }

        rttStateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
    }
    else
    {
        rttStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
    }

    // attach the overlay graph to the RTT camera.
    if ( _overlayGraph.valid() && ( _overlayGraph->getNumParents() == 0 || _overlayGraph->getParent(0) != pvd._rttCamera.get() ))
    {
        if ( pvd._rttCamera->getNumChildren() > 0 )
            pvd._rttCamera->replaceChild( 0, _overlayGraph.get() );
        else
            pvd._rttCamera->addChild( _overlayGraph.get() );
    }

    // overlay geometry is rendered with no depth testing, and in the order it's found in the
    // scene graph... until further notice...
    rttStateSet->setMode(GL_DEPTH_TEST, 0);
    rttStateSet->setBinName( "TraversalOrderBin" );


    // assemble the subgraph stateset:
    pvd._subgraphStateSet = new osg::StateSet();

    pvd._subgraphStateSet->setTextureAttributeAndModes( *_textureUnit, projTexture, osg::StateAttribute::ON );
    
    if ( _useShaders )
    {            
        // GPU path
        initSubgraphShaders( pvd );
    }
    else
    {
        // FFP path
        pvd._texGen = new osg::TexGen();
        pvd._texGen->setMode( osg::TexGen::EYE_LINEAR );
        pvd._subgraphStateSet->setTextureAttributeAndModes( *_textureUnit, pvd._texGen.get(), 1 );

        osg::TexEnv* env = new osg::TexEnv();
        env->setMode( osg::TexEnv::DECAL );
        pvd._subgraphStateSet->setTextureAttributeAndModes( *_textureUnit, env, 1 );
    }
}