예제 #1
0
bool ShadowVolume::getLightPositionalState( osgUtil::CullVisitor& cv,
        const Light* light, Vec4& lightPos, Vec3& lightDir )
{
    if( !light )
        return false;

    // get positional state
    osgUtil::RenderStage* rs = cv.getRenderStage();
    osgUtil::PositionalStateContainer::AttrMatrixList& aml =
        rs->getPositionalStateContainer()->getAttrMatrixList();

    RefMatrix* matrix = NULL;
    bool found = false;

    // find the light and its matrix
    // note: it finds the last light occurence with its associated matrix
    for( osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
        itr != aml.end();
        ++itr )
    {
        const Light* l = dynamic_cast< const Light* >( itr->first.get() );
        if( l && l == light )
        {
            found = true;
            matrix = itr->second.get();
        }
    }

    if( !found )
        return false;

    // transform light to world space
    Matrix localToWorld = Matrix::inverse( *cv.getModelViewMatrix() );
    if( matrix ) localToWorld.preMult( *matrix );

    lightPos = light->getPosition();

    if( lightPos[3] == 0 )
        lightDir.set( -lightPos[0], -lightPos[1], -lightPos[2] );
    else
        lightDir = light->getDirection();

    lightPos = lightPos * localToWorld;
    lightDir = Matrix::transform3x3( lightDir, localToWorld );
    lightDir.normalize();

    return true;
}
void ParallelSplitShadowMap::cull(osgUtil::CullVisitor& cv){
    // record the traversal mask on entry so we can reapply it later.
    unsigned int traversalMask = cv.getTraversalMask();
    osgUtil::RenderStage* orig_rs = cv.getRenderStage();

#ifdef SHADOW_TEXTURE_GLSL
    PSSMShadowSplitTextureMap::iterator it=_PSSMShadowSplitTextureMap.begin();
#else
    // do traversal of shadow receiving scene which does need to be decorated by the shadow map
    for (PSSMShadowSplitTextureMap::iterator it=_PSSMShadowSplitTextureMap.begin();it!=_PSSMShadowSplitTextureMap.end();it++)
#endif
    {
        PSSMShadowSplitTexture pssmShadowSplitTexture = it->second;
        cv.pushStateSet(pssmShadowSplitTexture._stateset.get());

        //////////////////////////////////////////////////////////////////////////
        // DEBUG
        if ( _displayTexturesGroupingNode ) {
            cv.pushStateSet(pssmShadowSplitTexture._debug_stateset.get());
        }
        //////////////////////////////////////////////////////////////////////////

        _shadowedScene->osg::Group::traverse(cv);

        cv.popStateSet();

    }

    // need to compute view frustum for RTT camera.
    // get the bounds of the model.
    osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
    cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());
    _shadowedScene->osg::Group::traverse(cbbv);

    //////////////////////////////////////////////////////////////////////////
    const osg::Light* selectLight = 0;

    /// light pos and light direction
    osg::Vec4 lightpos;
    osg::Vec3 lightDirection;

    if ( ! _userLight ) {
        // try to find a light in the scene
        osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
        for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
            itr != aml.end();
            ++itr)
        {
            const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
            if (light)
            {
                osg::RefMatrix* matrix = itr->second.get();
                if (matrix) lightpos = light->getPosition() * (*matrix);
                else lightpos = light->getPosition();
                if (matrix) lightDirection = light->getDirection() * (*matrix);
                else lightDirection = light->getDirection();

                selectLight = light;
            }
        }

        osg::Matrix eyeToWorld;
        eyeToWorld.invert(*cv.getModelViewMatrix());

        lightpos = lightpos * eyeToWorld;
        lightDirection = lightDirection * eyeToWorld;
    }else{
        // take the user light as light source
        lightpos = _userLight->getPosition();
        lightDirection = _userLight->getDirection();
        selectLight = _userLight.get();
    }

    if (selectLight)
    {

        // do traversal of shadow receiving scene which does need to be decorated by the shadow map
        //unsigned int iMaxSplit = _PSSMShadowSplitTextureMap.size();

        for (PSSMShadowSplitTextureMap::iterator it=_PSSMShadowSplitTextureMap.begin();it!=_PSSMShadowSplitTextureMap.end();it++)
        {
            PSSMShadowSplitTexture pssmShadowSplitTexture = it->second;


            //////////////////////////////////////////////////////////////////////////
            // SETUP pssmShadowSplitTexture for rendering
            //
            lightDirection.normalize();
            pssmShadowSplitTexture._lightDirection = lightDirection;
            pssmShadowSplitTexture._cameraView    = cv.getRenderInfo().getView()->getCamera()->getViewMatrix();
            pssmShadowSplitTexture._cameraProj    = cv.getRenderInfo().getView()->getCamera()->getProjectionMatrix();

            //////////////////////////////////////////////////////////////////////////
            // CALCULATE



            // Calculate corner points of frustum split
            //
            // To avoid edge problems, scale the frustum so
            // that it's at least a few pixels larger
            //
            osg::Vec3d pCorners[8];
            calculateFrustumCorners(pssmShadowSplitTexture,pCorners);

            // Init Light (Directional Light)
            //
            calculateLightInitialPosition(pssmShadowSplitTexture,pCorners);

            // Calculate near and far for light view
            //
            calculateLightNearFarFormFrustum(pssmShadowSplitTexture,pCorners);

            // Calculate view and projection matrices
            //
            calculateLightViewProjectionFormFrustum(pssmShadowSplitTexture,pCorners);

            //////////////////////////////////////////////////////////////////////////
            // set up shadow rendering camera
            pssmShadowSplitTexture._camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);

            //////////////////////////////////////////////////////////////////////////
            // DEBUG
            if ( _displayTexturesGroupingNode ) {
                pssmShadowSplitTexture._debug_camera->setViewMatrix(pssmShadowSplitTexture._camera->getViewMatrix());
                pssmShadowSplitTexture._debug_camera->setProjectionMatrix(pssmShadowSplitTexture._camera->getProjectionMatrix());
                pssmShadowSplitTexture._debug_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
            }

            //////////////////////////////////////////////////////////////////////////
            // compute the matrix which takes a vertex from local coords into tex coords
            // will use this later to specify osg::TexGen..

            osg::Matrix MVPT = pssmShadowSplitTexture._camera->getViewMatrix() *
                pssmShadowSplitTexture._camera->getProjectionMatrix() *
                osg::Matrix::translate(1.0,1.0,1.0) *
                osg::Matrix::scale(0.5,0.5,0.5);

            pssmShadowSplitTexture._texgen->setMode(osg::TexGen::EYE_LINEAR);
            pssmShadowSplitTexture._texgen->setPlanesFromMatrix(MVPT);
            //////////////////////////////////////////////////////////////////////////


            //////////////////////////////////////////////////////////////////////////
            cv.setTraversalMask( traversalMask & getShadowedScene()->getCastsShadowTraversalMask() );

            // do RTT camera traversal
            pssmShadowSplitTexture._camera->accept(cv);

            //////////////////////////////////////////////////////////////////////////
            // DEBUG
            if ( _displayTexturesGroupingNode ) {
                pssmShadowSplitTexture._debug_camera->accept(cv);
            }


            orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(pssmShadowSplitTexture._textureUnit, cv.getModelViewMatrix(), pssmShadowSplitTexture._texgen.get());


        }
    } // if light



    // reapply the original traversal mask
    cv.setTraversalMask( traversalMask );
}
예제 #3
0
파일: ShadowMap.cpp 프로젝트: 4ker/osg
void ShadowMap::cull(osgUtil::CullVisitor& cv)
{
    // record the traversal mask on entry so we can reapply it later.
    unsigned int traversalMask = cv.getTraversalMask();

    osgUtil::RenderStage* orig_rs = cv.getRenderStage();

    // do traversal of shadow receiving scene which does need to be decorated by the shadow map
    {
        cv.pushStateSet(_stateset.get());

        _shadowedScene->osg::Group::traverse(cv);

        cv.popStateSet();

    }

    // need to compute view frustum for RTT camera.
    // 1) get the light position
    // 2) get the center and extents of the view frustum

    const osg::Light* selectLight = 0;
    osg::Vec4 lightpos;
    osg::Vec3 lightDir;

    //MR testing giving a specific light
    osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
    for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
        itr != aml.end();
        ++itr)
    {
        const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
        if (light)
        {
            if( _light.valid()) {
                if( _light.get() == light )
                    selectLight = light;
                else
                    continue;
            }
            else
                selectLight = light;

            osg::RefMatrix* matrix = itr->second.get();
            if (matrix)
            {
                lightpos = light->getPosition() * (*matrix);
                lightDir = osg::Matrix::transform3x3( light->getDirection(), *matrix );
            }
            else
            {
                lightpos = light->getPosition();
                lightDir = light->getDirection();
            }

        }
    }

    osg::Matrix eyeToWorld;
    eyeToWorld.invert(*cv.getModelViewMatrix());

    lightpos = lightpos * eyeToWorld;
    lightDir = osg::Matrix::transform3x3( lightDir, eyeToWorld );
    lightDir.normalize();

    if (selectLight)
    {

        // set to ambient on light to black so that the ambient bias uniform can take it's affect
        const_cast<osg::Light*>(selectLight)->setAmbient(osg::Vec4(0.0f,0.0f,0.0f,1.0f));

        //std::cout<<"----- VxOSG::ShadowMap selectLight spot cutoff "<<selectLight->getSpotCutoff()<<std::endl;

        float fov = selectLight->getSpotCutoff() * 2;
        if(fov < 180.0f)   // spotlight, then we don't need the bounding box
        {
            osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());
            _camera->setProjectionMatrixAsPerspective(fov, 1.0, 0.1, 1000.0);
            _camera->setViewMatrixAsLookAt(position,position+lightDir,computeOrthogonalVector(lightDir));
        }
        else
        {
            // get the bounds of the model.
            osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
            cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());

            _shadowedScene->osg::Group::traverse(cbbv);

            osg::BoundingBox bb = cbbv.getBoundingBox();

            if (lightpos[3]!=0.0)   // point light
            {
                osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());

                float centerDistance = (position-bb.center()).length();

                float znear = centerDistance-bb.radius();
                float zfar  = centerDistance+bb.radius();
                float zNearRatio = 0.001f;
                if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;

                float top   = (bb.radius()/centerDistance)*znear;
                float right = top;

                _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
                _camera->setViewMatrixAsLookAt(position,bb.center(),computeOrthogonalVector(bb.center()-position));
            }
            else    // directional light
            {
                // make an orthographic projection
                osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z());
                lightDir.normalize();

                // set the position far away along the light direction
                osg::Vec3 position = bb.center() + lightDir * bb.radius() * 2;

                float centerDistance = (position-bb.center()).length();

                float znear = centerDistance-bb.radius();
                float zfar  = centerDistance+bb.radius();
                float zNearRatio = 0.001f;
                if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;

                float top   = bb.radius();
                float right = top;

                _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar);
                _camera->setViewMatrixAsLookAt(position,bb.center(),computeOrthogonalVector(lightDir));
            }


        }

        cv.setTraversalMask( traversalMask &
            getShadowedScene()->getCastsShadowTraversalMask() );

        // do RTT camera traversal
        _camera->accept(cv);

        _texgen->setMode(osg::TexGen::EYE_LINEAR);

#if IMPROVE_TEXGEN_PRECISION
        // compute the matrix which takes a vertex from local coords into tex coords
        // We actually use two matrices one used to define texgen
        // and second that will be used as modelview when appling to OpenGL
        _texgen->setPlanesFromMatrix( _camera->getProjectionMatrix() *
                                      osg::Matrix::translate(1.0,1.0,1.0) *
                                      osg::Matrix::scale(0.5f,0.5f,0.5f) );

        // Place texgen with modelview which removes big offsets (making it float friendly)
        osg::RefMatrix * refMatrix = new osg::RefMatrix
            ( _camera->getInverseViewMatrix() * *cv.getModelViewMatrix() );

        cv.getRenderStage()->getPositionalStateContainer()->
             addPositionedTextureAttribute( _shadowTextureUnit, refMatrix, _texgen.get() );
#else
        // compute the matrix which takes a vertex from local coords into tex coords
        // will use this later to specify osg::TexGen..
        osg::Matrix MVPT = _camera->getViewMatrix() *
               _camera->getProjectionMatrix() *
               osg::Matrix::translate(1.0,1.0,1.0) *
               osg::Matrix::scale(0.5f,0.5f,0.5f);

        _texgen->setPlanesFromMatrix(MVPT);

        orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_shadowTextureUnit, cv.getModelViewMatrix(), _texgen.get());
#endif
    } // if(selectLight)


    // reapply the original traversal mask
    cv.setTraversalMask( traversalMask );
}
예제 #4
0
void SoftShadowMap::cull(osgUtil::CullVisitor& cv)
{
    // record the traversal mask on entry so we can reapply it later.
    unsigned int traversalMask = cv.getTraversalMask();

    osgUtil::RenderStage* orig_rs = cv.getRenderStage();

    // do traversal of shadow receiving scene which does need to be decorated by the shadow map
    {
        cv.pushStateSet(_stateset.get());

        _shadowedScene->osg::Group::traverse(cv);

        cv.popStateSet();

    }

    // need to compute view frustum for RTT camera.
    // 1) get the light position
    // 2) get the center and extents of the view frustum

    const osg::Light* selectLight = 0;
    osg::Vec4 lightpos;

    osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
    for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
        itr != aml.end();
        ++itr)
    {
        const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
        if (light)
        {
            osg::RefMatrix* matrix = itr->second.get();
            if (matrix) lightpos = light->getPosition() * (*matrix);
            else lightpos = light->getPosition();

            selectLight = light;
        }
    }

    osg::Matrix eyeToWorld;
    eyeToWorld.invert(*cv.getModelViewMatrix());

    lightpos = lightpos * eyeToWorld;

    if (selectLight)
    {
        // get the bounds of the model.
        osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
        cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());

        _shadowedScene->osg::Group::traverse(cbbv);

        osg::BoundingBox bb = cbbv.getBoundingBox();


        osg::Vec3 position;

        if (lightpos[3]!=0.0)
        {
            position.set(lightpos.x(), lightpos.y(), lightpos.z());
        }
        else
        {
            // make an orthographic projection
            osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z());
            lightDir.normalize();

            // set the position far away along the light direction
            position = lightDir * bb.radius()  * 20;
        }

        float centerDistance = (position-bb.center()).length();

        float znear = centerDistance-bb.radius();
        float zfar  = centerDistance+bb.radius();
        float zNearRatio = 0.001f;
        if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;

        float top   = bb.radius();
        float right = top;

        _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
        _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar);
        _camera->setViewMatrixAsLookAt(position, bb.center(), osg::Vec3(0.0f,1.0f,0.0f));

        // compute the matrix which takes a vertex from local coords into tex coords
        // will use this later to specify osg::TexGen..
        osg::Matrix MVPT = _camera->getViewMatrix() *
                           _camera->getProjectionMatrix() *
                           osg::Matrix::translate(1.0,1.0,1.0) *
                           osg::Matrix::scale(0.5,0.5,0.5+_bias);

        _texgen->setMode(osg::TexGen::EYE_LINEAR);
        _texgen->setPlanesFromMatrix(MVPT);

        cv.setTraversalMask( traversalMask &
                             getShadowedScene()->getCastsShadowTraversalMask() );

        // do RTT camera traversal
        _camera->accept(cv);

        orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, cv.getModelViewMatrix(), _texgen.get());
    }


    // reapply the original traversal mask
    cv.setTraversalMask( traversalMask );
}
예제 #5
0
void ShadowVolume::cull( osgUtil::CullVisitor& cv )
{
   //notify(NOTICE)<<"CULL BEGIN"<<std::endl;
    // if no light, render scene default way
    if( !_light ) {
        _shadowedScene->Group::traverse( cv );
        return;
    }

    // pass 4: add light using stencil
    // The pass is culled in the first place as it is always culled (in contrary to pass 1).
    // Its traversed lights are used in following getLightPositionalState.
    // Note: traversing order of passes 1 to 4 does not matter. Rendering order is given
    //       by RenderBin's setRenderBinDetails().
    cv.pushStateSet( _ss4 );
    _shadowedScene->Group::traverse( cv );
    cv.popStateSet();

    // clear stencil buffer - bin number 1 schedules it before 2nd and 3rd pass
    if( _clearStencil)
       //_clearDrawable->setBufferMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
       cv.addDrawable( _clearDrawable, cv.getModelViewMatrix() );

    // pass 1: ambient pass
    if(!_ambientPassDisabled)
    {
       cv.pushStateSet( _ss1 );
       _shadowedScene->Group::traverse( cv );
       cv.popStateSet();
    }

    // get light positional state,
    // if no light, return
    Vec4 lightPos;
    Vec3 lightDir;
    if( !getLightPositionalState( cv, _light, lightPos, lightDir ) )
        return;

    /******************PASS 2,3/: Shadow geometry into stencil buffer*********************/
    
    if(   _mode == ShadowVolumeGeometryGenerator::CPU_FIND_GPU_EXTRUDE
       || _mode == ShadowVolumeGeometryGenerator::GPU_RAW
       || _mode == ShadowVolumeGeometryGenerator::GPU_SILHOUETTE)
    {    
       //notify(NOTICE)<<"LIGHTPOS: "<<lightPos.x()<<" "<<lightPos.y()<<" "<<lightPos.z()<<" "<<std::endl;
       _lightPosUniform->set(lightPos);
    }

    if(_updateStrategy == UPDATE_EACH_FRAME)
      _svgg.dirty();

   if(_svgg.isDirty()){
          //_svgg.clearGeometry();
          _svgg.setup(lightPos);
          _shadowedScene->Group::traverse( _svgg );
   }

   if(_mode == ShadowVolumeGeometryGenerator::SILHOUETTES_ONLY){
      cv.pushStateSet(_ssd);
      ref_ptr< Drawable > d = _svgg.createGeometry();
      d->setUseDisplayList( false );
      ref_ptr< Geode > geode = new Geode;
      geode->addDrawable( d );
      geode->accept( cv );
      cv.popStateSet();
      return;
   }

   bool twoSidedStencil = _stencilImplementation == STENCIL_TWO_SIDED;
   if( _stencilImplementation == STENCIL_AUTO )
   {
      GraphicsContext *gc = cv.getState()->getGraphicsContext();
      if( gc->isGLExtensionSupported( 2.0, "GL20_separate_stencil" ) ||
          gc->isGLExtensionSupported( "GL_EXT_stencil_two_side" ) ||
          gc->isGLExtensionSupported( "GL_ATI_separate_stencil" ) )
      {
         twoSidedStencil = true;
      }
   }

   if(twoSidedStencil){
      cv.pushStateSet( _ss23 );

      ref_ptr< Drawable > d = _svgg.createGeometry();
      d->setUseDisplayList( false );
      ref_ptr< Geode > geode = new Geode;
      geode->addDrawable( d );
      geode->accept( cv );

      cv.popStateSet();

      if(_svgg.getMethod() == ShadowVolumeGeometryGenerator::ZFAIL){
         if(   _svgg.getMode() == ShadowVolumeGeometryGenerator::CPU_RAW 
             || _svgg.getMode() == ShadowVolumeGeometryGenerator::CPU_SILHOUETTE)
          {
            ref_ptr< Drawable > caps;
            caps = _svgg.getCapsGeometry();
            caps->setUseDisplayList( false );
            ref_ptr< Geode > geode_caps = new Geode;
            geode_caps->addDrawable( caps );

            cv.pushStateSet( _ss23_caps );
            geode_caps->accept( cv );
            cv.popStateSet();
         }
         else if(   _svgg.getMode() == ShadowVolumeGeometryGenerator::GPU_RAW 
                 || _svgg.getMode() == ShadowVolumeGeometryGenerator::GPU_SILHOUETTE)
         {
            cv.pushStateSet( _ss23_caps );
            geode->accept( cv );
            cv.popStateSet();
         }
      }
   }
   else{
       ref_ptr< Drawable > d = _svgg.createGeometry();
       d->setUseDisplayList( false );
       ref_ptr< Geode > geode = new Geode;
       geode->addDrawable( d );

       cv.pushStateSet( _ss2 );               
       geode->accept( cv );
       cv.popStateSet();

       // pass 3
       cv.pushStateSet( _ss3 );
       geode->accept( cv );
       cv.popStateSet();
   
       if(_svgg.getMethod() == ShadowVolumeGeometryGenerator::ZFAIL){          
          if(   _svgg.getMode() == ShadowVolumeGeometryGenerator::CPU_RAW 
             || _svgg.getMode() == ShadowVolumeGeometryGenerator::CPU_SILHOUETTE)
          {
             ref_ptr< Drawable > caps;
             ref_ptr< Geode > geode_caps = new Geode;
             caps = _svgg.getCapsGeometry();
             caps->setUseDisplayList( false );
             geode_caps->addDrawable( caps );

             cv.pushStateSet( _ss2_caps );               
             geode_caps->accept( cv );
             cv.popStateSet();

             cv.pushStateSet( _ss3_caps );               
             geode_caps->accept( cv );
             cv.popStateSet();
          }
          else if(   _svgg.getMode() == ShadowVolumeGeometryGenerator::GPU_RAW 
                  || _svgg.getMode() == ShadowVolumeGeometryGenerator::GPU_SILHOUETTE)
          {
             //_just_caps->set(1);
             cv.pushStateSet( _ss2_caps );
             geode->accept( cv );
             cv.popStateSet();

             cv.pushStateSet( _ss3_caps );
             geode->accept( cv );
             cv.popStateSet();
             //_just_caps->set(0);
          }
       }
               
   }

    //notify(NOTICE)<<"CULL END!!!"<<std::endl;
}
예제 #6
0
파일: ShadowVolume.cpp 프로젝트: AdriCS/osg
void ShadowVolume::cull(osgUtil::CullVisitor& cv)
{

    osg::ref_ptr<osgUtil::RenderBin> original_bin = cv.getCurrentRenderBin();

    osg::ref_ptr<osgUtil::RenderBin> new_bin = original_bin->find_or_insert(0,"RenderBin");

    cv.setCurrentRenderBin(new_bin.get());

    _shadowedScene->osg::Group::traverse(cv);

    cv.setCurrentRenderBin(original_bin.get());

    osgUtil::RenderBin::RenderBinList::iterator itr =  new_bin->getRenderBinList().find(1000);
    osg::ref_ptr<osgUtil::RenderBin> shadowVolumeBin;
    if (itr != new_bin->getRenderBinList().end())
    {
        shadowVolumeBin = itr->second;

        if (shadowVolumeBin.valid())
        {
            //OSG_NOTICE<<"Found shadow volume bin, now removing it"<<std::endl;
            new_bin->getRenderBinList().erase(itr);
        }
    }

    if (shadowVolumeBin.valid())
    {
        original_bin->setStateSet(_ss1.get());

        osgUtil::RenderStage* orig_rs = cv.getRenderStage();
        osgUtil::RenderStage* new_rs = new osgUtil::RenderStage;
        orig_rs->addPostRenderStage(new_rs);

        new_rs->setViewport(orig_rs->getViewport());
        new_rs->setClearColor(orig_rs->getClearColor());
        new_rs->setClearMask(GL_STENCIL_BUFFER_BIT);
        new_rs->setDrawBuffer(orig_rs->getDrawBuffer(), orig_rs->getDrawBufferApplyMask());
        new_rs->setReadBuffer(orig_rs->getReadBuffer(), orig_rs->getReadBufferApplyMask());
        new_rs->setColorMask(orig_rs->getColorMask());

        osg::Vec4 lightpos;

        osg::ref_ptr<osgUtil::PositionalStateContainer> ps = new osgUtil::PositionalStateContainer;
        new_rs->setPositionalStateContainer(ps.get());

        const osg::Light* selectLight = 0;

        osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
        for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
            itr != aml.end();
            ++itr)
        {
            const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
            if (light)
            {
                osg::RefMatrix* matrix = itr->second.get();
                if (matrix) lightpos = light->getPosition() * (*matrix);
                else lightpos = light->getPosition();

                selectLight = light;
            }
            else
            {
                ps->addPositionedAttribute(itr->second.get(), itr->first.get());
            }
        }

        _ambientLight->setPosition(lightpos);

        orig_rs->addPositionedAttribute(0,_ambientLight.get());

        _diffuseLight->setPosition(lightpos);
        if (selectLight)
        {
            _ambientLight->setAmbient(selectLight->getAmbient());

            _diffuseLight->setDiffuse(selectLight->getDiffuse());
            _diffuseLight->setSpecular(selectLight->getSpecular());
            _diffuseLight->setDirection(selectLight->getDirection());
            _diffuseLight->setConstantAttenuation(selectLight->getConstantAttenuation());
            _diffuseLight->setLinearAttenuation(selectLight->getLinearAttenuation());
            _diffuseLight->setQuadraticAttenuation(selectLight->getQuadraticAttenuation());
            _diffuseLight->setSpotExponent(selectLight->getSpotExponent());
            _diffuseLight->setSpotCutoff(selectLight->getSpotCutoff());
        }
        ps->addPositionedAttribute(0, _diffuseLight.get());

        if (_lightpos != lightpos && _dynamicShadowVolumes)
        {
            _lightpos = lightpos;

            osg::Matrix eyeToWorld;
            eyeToWorld.invert(*cv.getModelViewMatrix());

            _occluder->computeShadowVolumeGeometry(lightpos * eyeToWorld, *_shadowVolume);
        }

        if (shadowVolumeBin.valid())
        {
            // new_rs->setStateSet(_mainShadowStateSet.get());
            new_rs->getRenderBinList()[0] = shadowVolumeBin;
            shadowVolumeBin->setStateSet(_shadowVolumeStateSet.get());

            osg::ref_ptr<osgUtil::RenderBin> nested_bin = new_rs->find_or_insert(1,"RenderBin");
            nested_bin->getRenderBinList()[0] = new_bin;
            nested_bin->setStateSet(_shadowedSceneStateSet.get());
        }
    }


}
bool
GraticuleLabelingEngine::cullTraverse(osgUtil::CullVisitor& nv, CameraData& data)
{    
    osg::Camera* cam = nv.getCurrentCamera();

    // Don't draw the labels if we are too far from North-Up:
    double heading = getCameraHeading(cam->getViewMatrix());
    if (osg::RadiansToDegrees(fabs(heading)) > 7.0)
        return false;

    // Initialize the label pool for this camera if we have not done so:
    if (data.xLabels.empty())
    {
        for (unsigned i = 0; i < MAX_LABELS; ++i)
        {
            LabelNode* label = new LabelNode();
            label->setDynamic(true);
            label->setStyle(_xLabelStyle);
            label->setHorizonCulling(false);
            label->setOcclusionCulling(false);
            data.xLabels.push_back(label);
        }

        for (unsigned i = 0; i < MAX_LABELS; ++i)
        {
            LabelNode* label = new LabelNode();
            label->setDynamic(true);
            label->setStyle(_yLabelStyle);
            label->setHorizonCulling(false);
            label->setOcclusionCulling(false);
            data.yLabels.push_back(label);
        }
    }

    // Start out with all labels off. We will then turn back on the ones we use:
    for (unsigned i = 0; i < MAX_LABELS; ++i)
    {
        data.xLabels[i]->setNodeMask(0);
        data.yLabels[i]->setNodeMask(0);
    }

    // Intersect the corners of the view frustum with the ellipsoid.
    // This will yield the approximate geo-extent of the view.
    // TODO: graduate this to the core if generally useful - could be helpful
    // for displaying the extent of the current view.

    // Calculate the "clip to world" matrix = MVPinv.
    osg::Matrix MVP = (*nv.getModelViewMatrix()) * cam->getProjectionMatrix();
    osg::Matrix MVPinv;
    MVPinv.invert(MVP);

    EllipsoidIntersector ellipsoid(_srs->getEllipsoid());

    // For each corner, transform the clip coordinates at the near and far
    // planes into world space and intersect that line with the ellipsoid:
    osg::Vec3d p0, p1;

    // find the lower-left corner of the frustum:
    osg::Vec3d LL_world;
    p0 = osg::Vec3d(-1, -1, -1) * MVPinv;
    p1 = osg::Vec3d(-1, -1, +1) * MVPinv;
    bool LL_ok = ellipsoid.intersectLine(p0, p1, LL_world);
    if (!LL_ok)
        return false;

    // find the upper-left corner of the frustum:
    osg::Vec3d UL_world;
    p0 = osg::Vec3d(-1, +1, -1) * MVPinv;
    p1 = osg::Vec3d(-1, +1, +1) * MVPinv;
    bool UL_ok = ellipsoid.intersectLine(p0, p1, UL_world);
    if (!UL_ok)
        return false;

    // find the lower-right corner of the frustum:
    osg::Vec3d LR_world;
    p0 = osg::Vec3d(+1, -1, -1) * MVPinv;
    p1 = osg::Vec3d(+1, -1, +1) * MVPinv;
    bool LR_ok = ellipsoid.intersectLine(p0, p1, LR_world);
    if (!LR_ok)
        return false;

    // Use this for clamping geopoints to the edges of the frustum:
    ClipSpace window(MVP, MVPinv);

    return updateLabels(LL_world, UL_world, LR_world, window, data);
}