osgEarth 2.1.1
Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes

osgEarth::Symbology::StencilVolumeNode Class Reference

Inheritance diagram for osgEarth::Symbology::StencilVolumeNode:
Collaboration diagram for osgEarth::Symbology::StencilVolumeNode:

List of all members.

Public Member Functions

 StencilVolumeNode (bool preRenderChildrenToDepthBuffer=false, bool inverted=false)
 StencilVolumeNode (const StencilVolumeNode &rhs, const osg::CopyOp &op=osg::CopyOp::DEEP_COPY_ALL)
 META_Node (osgEarth::Symbology, StencilVolumeNode)
virtual void traverse (osg::NodeVisitor &nv)
int setBaseRenderBin (int bin)
void addVolumes (osg::Node *node, bool onNextUpdate=true)
virtual bool addChild (Node *child)
virtual bool insertChild (unsigned int index, Node *child)
virtual bool removeChildren (unsigned int pos, unsigned int numChildrenToRemove)
virtual bool replaceChild (Node *origChild, Node *newChild)
virtual bool setChild (unsigned int i, Node *node)
virtual osg::BoundingSphere computeBound () const

Static Public Member Functions

static osg::Node * createFullScreenQuad (const osg::Vec4f &color)

Protected Member Functions

void init ()
void addQueuedVolumes ()

Protected Attributes

osg::ref_ptr< osg::Group > _root
osg::Group * _stencilGroup1
osg::Group * _stencilGroup2
osg::Group * _depthPass
osg::Group * _renderPass
bool _inverted
bool _preRenderChildrenToDepthBuffer
Threading::Mutex _addVolumesMutex
std::queue< osg::ref_ptr
< osg::Node > > 
_volumesToAdd

Detailed Description

Definition at line 32 of file StencilVolumeNode.


Constructor & Destructor Documentation

StencilVolumeNode::StencilVolumeNode ( bool  preRenderChildrenToDepthBuffer = false,
bool  inverted = false 
)

Constructs a stencil masking node.

Parameters:
preRenderChildrenToDepthBufferNormally, this node will render the stencil volumes first and then render the children (which will be masked by the stencil). If you need to pre-render the children to the depth buffer, set this to TRUE. You need to do this is you are creating a straight render mask.
invertedInverts the stencil buffer, masking the opposite pixels that would normally be masked.

Definition at line 86 of file StencilVolumeNode.cpp.

                                                                                         :
osgEarth::MaskNode(),
_stencilGroup1( 0L ),
_stencilGroup2( 0L ),
_depthPass( 0L ),
_renderPass( 0L ),
_inverted( inverted ),
_preRenderChildrenToDepthBuffer( preRenderChildrenToDepthBuffer )
{
    init();
}

Here is the call graph for this function:

StencilVolumeNode::StencilVolumeNode ( const StencilVolumeNode rhs,
const osg::CopyOp &  op = osg::CopyOp::DEEP_COPY_ALL 
)

Member Function Documentation

bool StencilVolumeNode::addChild ( Node *  child) [virtual]

Override all the osg::Group methods:

Definition at line 174 of file StencilVolumeNode.cpp.

                                         {
    if ( !child ) return false;
    dirtyBound();
    if ( _depthPass )  _depthPass->addChild( child );
    return _renderPass->addChild( child );
}
void StencilVolumeNode::addQueuedVolumes ( ) [protected]

Definition at line 153 of file StencilVolumeNode.cpp.

{
    Threading::ScopedMutexLock lock( _addVolumesMutex );
    while( !_volumesToAdd.empty() )
    {
        osg::Node* node = _volumesToAdd.front().get();

        if ( _stencilGroup1 )
            _stencilGroup1->addChild( node );
        if ( _stencilGroup2 )
            _stencilGroup2->addChild( node );        

        _volumesToAdd.pop();
    }
    
    ADJUST_UPDATE_TRAV_COUNT( this, -1 );
}

Here is the caller graph for this function:

void StencilVolumeNode::addVolumes ( osg::Node *  node,
bool  onNextUpdate = true 
)

Definition at line 135 of file StencilVolumeNode.cpp.

{
    if ( onNextUpdate )
    {
        Threading::ScopedMutexLock lock( _addVolumesMutex );
        _volumesToAdd.push( node );
        ADJUST_UPDATE_TRAV_COUNT( this, 1 );
    }
    else
    {
        if ( _stencilGroup1 )
            _stencilGroup1->addChild( node );
        if ( _stencilGroup2 )
            _stencilGroup2->addChild( node );
    }
}
osg::BoundingSphere StencilVolumeNode::computeBound ( ) const [virtual]

Definition at line 207 of file StencilVolumeNode.cpp.

                                      {
    if ( _depthPass ) return _depthPass->computeBound();
    else return _renderPass->computeBound();
}
osg::Node * StencilVolumeNode::createFullScreenQuad ( const osg::Vec4f &  color) [static]

Generates a full screen quad that you can use to colorize stencil volumes

Definition at line 47 of file StencilVolumeNode.cpp.

{
    // make a full screen quad:
    osg::Geometry* quad = new osg::Geometry();
    osg::Vec3Array* verts = new osg::Vec3Array(4);
    (*verts)[0].set( 0, 1, 0 );
    (*verts)[1].set( 0, 0, 0 );
    (*verts)[2].set( 1, 0, 0 );
    (*verts)[3].set( 1, 1, 0 );
    quad->setVertexArray( verts );
    quad->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
    osg::Vec4Array* colors = new osg::Vec4Array(1);
    (*colors)[0] = color;
    quad->setColorArray( colors );
    quad->setColorBinding( osg::Geometry::BIND_OVERALL );
    osg::Geode* quad_geode = new osg::Geode();
    quad_geode->addDrawable( quad );

    osg::StateSet* quad_ss = quad->getOrCreateStateSet();
    quad_ss->setMode( GL_CULL_FACE, OFF_PROTECTED );
    quad_ss->setMode( GL_DEPTH_TEST, OFF_PROTECTED );
    quad_ss->setMode( GL_LIGHTING, OFF_PROTECTED );
    osg::MatrixTransform* abs = new osg::MatrixTransform();
    abs->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
    abs->setMatrix( osg::Matrix::identity() );
    abs->addChild( quad_geode );

    osg::Projection* proj = new osg::Projection();
    proj->setMatrix( osg::Matrix::ortho(0, 1, 0, 1, 0, -1) );
    proj->addChild( abs );

    proj->getOrCreateStateSet()->setMode( GL_BLEND, 1 );    

    return proj;
}
void StencilVolumeNode::init ( ) [protected]

Definition at line 225 of file StencilVolumeNode.cpp.

{
    _root = new osg::Group();
    int baseBin = 100;

    // First, if we need to render the children to the depth buffer, create a depth
    // buffer only pass. This is necessary if we are masking out terrain, for example. We have
    // to populate the depth buffer before this algoritm can work.
    if ( _preRenderChildrenToDepthBuffer )
    {
        _depthPass = new osg::Group();
        _depthPass->setName( "StencilVolumeNode::depth_pass" );
        osg::StateSet* ss = _depthPass->getOrCreateStateSet();
        ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
        //ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
        ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS), ON_AND_PROTECTED);
        ss->setRenderBinDetails( baseBin++, "RenderBin" );

        _root->addChild( _depthPass );
    }

    // Create the stenciled geometry pass:

    // For now we are hard-coding these to what are hopefully "safe" values.
    // In the future we hope to rewrite this as a custom StencilVolumeNode that 
    // will automatically detect extension availability at draw time and choose
    // the optimal GL rendering path.
    const Capabilities& caps = osgEarth::Registry::instance()->getCapabilities();
    bool s_EXT_stencil_wrap     = caps.supportsStencilWrap(); //true;
    bool s_EXT_stencil_two_side = caps.supportsTwoSidedStencil(); //false;


    // zFail=true if more compute intensive, but lets you get inside the volume.
    // Again, a custom node will give us a better opportunity to choose between zFail and zPass based on
    // the eye location (you only need zFail if you camera is inside the volume).
    bool zFail = true;

    OE_DEBUG << "Stencil buffer wrap = " << s_EXT_stencil_wrap << std::endl;

    if ( s_EXT_stencil_two_side )
    {
        OE_DEBUG << "Two-sided stenciling" << std::endl;

        osg::StencilTwoSided::Operation incrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::INCR_WRAP : osg::StencilTwoSided::INCR;
        osg::StencilTwoSided::Operation decrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::DECR_WRAP : osg::StencilTwoSided::DECR;
        _stencilGroup1 = new osg::Group();
        //osg::Group* stencil_group = new osg::Group();
        osg::StateSet* ss = _stencilGroup1->getOrCreateStateSet();
        ss->setRenderBinDetails( baseBin++, "RenderBin" );

        if ( zFail )
        {
            osg::StencilTwoSided* stencil = new osg::StencilTwoSided();
            stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
            stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, incrOp, osg::StencilTwoSided::KEEP);

            stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
            stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, decrOp, osg::StencilTwoSided::KEEP);
            ss->setAttributeAndModes( stencil, ON_AND_PROTECTED );
        }
        else
        {
            osg::StencilTwoSided* stencil = new osg::StencilTwoSided();
            stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
            stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, incrOp);

            stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
            stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, decrOp);
            ss->setAttributeAndModes( stencil, ON_AND_PROTECTED );
        }

        ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
        ss->setAttributeAndModes(new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);

        _root->addChild( _stencilGroup1 );
    }
    else
    {
        OE_INFO << "One-sided stenciling" << std::endl;

        if ( !zFail )  // Z-Pass
        {
            _stencilGroup1 = new osg::Group();
            osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet();
            front_ss->setRenderBinDetails( baseBin++, "RenderBin" );

            // incrementing stencil op for front faces:
            osg::Stencil* front_stencil = new osg::Stencil();
            front_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u );
            osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR;
            front_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, incrOp );
            front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED );

            front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
            front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
            front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);

            _root->addChild( _stencilGroup1 );

            // decrementing stencil op for back faces:
            _stencilGroup2 = new osg::Group();
            osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet();
            back_ss->setRenderBinDetails( baseBin++, "RenderBin" );

            osg::Stencil* back_stencil = new osg::Stencil();
            back_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u );
            osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR;
            back_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, decrOp );
            back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED );

            back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
            back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED);
            back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);

            _root->addChild( _stencilGroup2 );    
        }
        else
        {
            // incrementing stencil op for back faces:
            {
                _stencilGroup1 = new osg::Group();
                osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet();
                front_ss->setRenderBinDetails( baseBin++, "RenderBin" );

                osg::Stencil* front_stencil = new osg::Stencil();
                front_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u );
                osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR;
                front_stencil->setOperation( osg::Stencil::KEEP, incrOp, osg::Stencil::KEEP );
                front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED );

                front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
                front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED);
                front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);

                _root->addChild( _stencilGroup1 );
            }

            // decrementing stencil buf for front faces
            {
                _stencilGroup2 = new osg::Group();
                osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet();
                back_ss->setRenderBinDetails( baseBin++, "RenderBin" );

                osg::Stencil* back_stencil = new osg::Stencil();
                back_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u );
                osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR;
                back_stencil->setOperation( osg::Stencil::KEEP, decrOp, osg::Stencil::KEEP );
                back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED );

                back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
                back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
                back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);

                _root->addChild( _stencilGroup2 );
            }
        }
    }
    

    // NOW build the full-screen quad mask that will paint the volume:

    _renderPass = new osg::Group();
    _renderPass->setName( "StencilVolumeNode::render_pass" );

    osg::Stencil* quad_stencil = new osg::Stencil();
    osg::Stencil::Function func = _inverted ? osg::Stencil::EQUAL : osg::Stencil::NOTEQUAL;
    quad_stencil->setFunction( func, 128, (unsigned int)~0 );
    // this will conveniently re-clear the stencil buffer in prep for the next pass:
    quad_stencil->setOperation( osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE );

    osg::StateSet* renderSS = _renderPass->getOrCreateStateSet();
    renderSS->setAttributeAndModes( quad_stencil, ON_AND_PROTECTED );
    renderSS->setRenderBinDetails( baseBin++, "RenderBin" );

    // if we did a pre-render depth pass, adjust the depth buffer function to account for that
    if ( _preRenderChildrenToDepthBuffer )
    {
        renderSS->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL ), osg::StateAttribute::ON );
    }

    // testing
    //renderSS->setMode( GL_DEPTH_TEST, OFF_AND_PROTECTED );
    //renderSS->setAttributeAndModes( new osg::Depth( osg::Depth::ALWAYS ), ON_AND_PROTECTED );

    _root->addChild( _renderPass );
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool StencilVolumeNode::insertChild ( unsigned int  index,
Node *  child 
) [virtual]

Definition at line 181 of file StencilVolumeNode.cpp.

                                                                {
    if ( !child ) return false;
    dirtyBound();
    if ( _depthPass ) _depthPass->insertChild( index, child );
    return _renderPass->insertChild( index, child );
}
osgEarth::Symbology::StencilVolumeNode::META_Node ( osgEarth::Symbology  ,
StencilVolumeNode   
)
bool StencilVolumeNode::removeChildren ( unsigned int  pos,
unsigned int  numChildrenToRemove 
) [virtual]

Definition at line 188 of file StencilVolumeNode.cpp.

                                                                                   {
    dirtyBound();
    if ( _depthPass ) _depthPass->removeChildren( pos, numChildrenToRemove );
    return _renderPass->removeChildren( pos, numChildrenToRemove );
}
bool StencilVolumeNode::replaceChild ( Node *  origChild,
Node *  newChild 
) [virtual]

Definition at line 194 of file StencilVolumeNode.cpp.

                                                                 {
    dirtyBound();
    if ( _depthPass ) _depthPass->replaceChild( origChild, newChild );
    return _renderPass->replaceChild( origChild, newChild );
}
int StencilVolumeNode::setBaseRenderBin ( int  bin)

Definition at line 113 of file StencilVolumeNode.cpp.

{
    if ( _depthPass )
    {
        _depthPass->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
    }
    if ( _stencilGroup1 )
    {
        _stencilGroup1->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
    }
    if ( _stencilGroup2 )
    {
        _stencilGroup2->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
    }
    if ( _renderPass )
    {
        _renderPass->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
    }
    return bin;
}
bool StencilVolumeNode::setChild ( unsigned int  i,
Node *  node 
) [virtual]

Definition at line 200 of file StencilVolumeNode.cpp.

                                                         {
    dirtyBound();
    if ( _depthPass ) _depthPass->setChild( i, node );
    return _renderPass->setChild( i, node );
}
void StencilVolumeNode::traverse ( osg::NodeVisitor &  nv) [virtual]

Definition at line 214 of file StencilVolumeNode.cpp.

{
    if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && _volumesToAdd.size() > 0 )
    {
        addQueuedVolumes();
    }

    _root->accept( nv );
}

Here is the call graph for this function:


Member Data Documentation

Definition at line 99 of file StencilVolumeNode.

Definition at line 94 of file StencilVolumeNode.

Definition at line 96 of file StencilVolumeNode.

Definition at line 97 of file StencilVolumeNode.

Definition at line 95 of file StencilVolumeNode.

osg::ref_ptr<osg::Group> osgEarth::Symbology::StencilVolumeNode::_root [protected]

Definition at line 91 of file StencilVolumeNode.

Definition at line 92 of file StencilVolumeNode.

Definition at line 93 of file StencilVolumeNode.

std::queue< osg::ref_ptr<osg::Node> > osgEarth::Symbology::StencilVolumeNode::_volumesToAdd [protected]

Definition at line 100 of file StencilVolumeNode.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines