예제 #1
0
osg::BoundingBox MinimalShadowMap::ViewData::computeShadowReceivingCoarseBounds()
{
    // Default slowest but most precise
    ShadowReceivingCoarseBoundAccuracy accuracy = DEFAULT_ACCURACY;

    MinimalShadowMap * msm = dynamic_cast< MinimalShadowMap* >( _st.get() );
    if( msm ) accuracy = msm->getShadowReceivingCoarseBoundAccuracy();

    if( accuracy == MinimalShadowMap::EMPTY_BOX )
    {
        // One may skip coarse scene bounds computation if light is infinite.
        // Empty box will be intersected with view frustum so in the end 
        // view frustum will be used as bounds approximation.
        // But if light is nondirectional and bounds come out too large 
        // they may bring the effect of almost 180 deg perspective set 
        // up for shadow camera. Such projection will significantly impact 
        // precision of further math.

        return osg::BoundingBox();
    }

    if( accuracy == MinimalShadowMap::BOUNDING_SPHERE )
    {
        // faster but less precise rough scene bound computation
        // however if compute near far is active it may bring quite good result
        osg::Camera * camera = _cv->getRenderStage()->getCamera();
        osg::Matrix m = camera->getViewMatrix() * _clampedProjection;

        ConvexPolyhedron frustum;
        frustum.setToUnitFrustum();
        frustum.transform( osg::Matrix::inverse( m ), m );

        osg::BoundingSphere bs =_st->getShadowedScene()->getBound();
        osg::BoundingBox bb;
        bb.expandBy( bs );
        osg::Polytope box;
        box.setToBoundingBox( bb );

        frustum.cut( box );

        // approximate sphere with octahedron. Ie first cut by box then 
        // additionaly cut with the same box rotated 45, 45, 45 deg.
        box.transform( // rotate box around its center
            osg::Matrix::translate( -bs.center() ) *
            osg::Matrix::rotate( osg::PI_4, 0, 0, 1 ) * 
            osg::Matrix::rotate( osg::PI_4, 1, 1, 0 ) * 
            osg::Matrix::translate( bs.center() ) );
        frustum.cut( box );
    
        return frustum.computeBoundingBox( );    
    }
    
    if( accuracy == MinimalShadowMap::BOUNDING_BOX ) // Default
    {
        // more precise method but slower method 
        // bound visitor traversal takes lot of time for complex scenes 
        // (note that this adds to cull time)

        osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
        cbbv.setTraversalMask(_st->getShadowedScene()->getCastsShadowTraversalMask());
        _st->getShadowedScene()->osg::Group::traverse(cbbv);

        return cbbv.getBoundingBox();
    }

    return osg::BoundingBox();
}
예제 #2
0
void MinimalShadowMap::ViewData::frameShadowCastingCamera
     ( const osg::Camera* cameraMain, osg::Camera* cameraShadow, int pass )
{
    osg::Matrix mvp =
        cameraShadow->getViewMatrix() * cameraShadow->getProjectionMatrix();

    ConvexPolyhedron polytope = _sceneReceivingShadowPolytope;
    std::vector<osg::Vec3d> points = _sceneReceivingShadowPolytopePoints;

    osg::BoundingBox bb = computeScenePolytopeBounds( mvp );

    // projection was trimmed above, need to recompute mvp
    if( bb.valid() && *_minLightMarginPtr > 0 ) {
        //        bb._max += osg::Vec3( 1, 1, 1 );
        //        bb._min -= osg::Vec3( 1, 1, 1 );

        osg::Matrix transform = osg::Matrix::inverse( mvp );

        // Code below was working only for directional lights ie when projection was ortho
        // osg::Vec3d normal = osg::Matrix::transform3x3( osg::Vec3d( 0,0,-1)., transfrom );

        // So I replaced it with safer code working with spot lights as well
        osg::Vec3d normal =
            osg::Vec3d(0,0,-1) * transform - osg::Vec3d(0,0,1) * transform;

        normal.normalize();
        _sceneReceivingShadowPolytope.extrude( normal * *_minLightMarginPtr );

        // Zero pass does crude shadowed scene hull approximation.
        // Its important to cut it to coarse light frustum properly
        // at this stage.
        // If not cut and polytope extends beyond shadow projection clip
        // space (-1..1), it may get "twisted" by precisely adjusted shadow cam
        // projection in second pass.

        if ( pass == 0 && _frameShadowCastingCameraPasses > 1 )
        { // Make sure extruded polytope does not extend beyond light frustum
            osg::Polytope lightFrustum;
            lightFrustum.setToUnitFrustum();
            lightFrustum.transformProvidingInverse( mvp );
            _sceneReceivingShadowPolytope.cut( lightFrustum );
        }

        _sceneReceivingShadowPolytopePoints.clear();
        _sceneReceivingShadowPolytope.getPoints
            ( _sceneReceivingShadowPolytopePoints );

        bb = computeScenePolytopeBounds( mvp );
    }

    setDebugPolytope( "extended",
        _sceneReceivingShadowPolytope, osg::Vec4( 1, 0.5, 0, 1 ), osg::Vec4( 1, 0.5, 0, 0.1 ) );

    _sceneReceivingShadowPolytope = polytope;
    _sceneReceivingShadowPolytopePoints = points;

    // Warning: Trim light projection at near plane may remove shadowing
    // from objects outside of view space but still casting shadows into it.
    // I have not noticed this issue so I left mask at default: all bits set.
    if( bb.valid() )
        trimProjection( cameraShadow->getProjectionMatrix(), bb, 1|2|4|8|16|32 );

    ///// Debuging stuff //////////////////////////////////////////////////////////
    setDebugPolytope( "scene", _sceneReceivingShadowPolytope, osg::Vec4(0,1,0,1) );


#if PRINT_SHADOW_TEXEL_TO_PIXEL_ERROR
    if( pass == 1 )
        displayShadowTexelToPixelErrors
            ( cameraMain, cameraShadow, &_sceneReceivingShadowPolytope );
#endif

    if( pass == _frameShadowCastingCameraPasses - 1 )
    {
#if 1
        {
            osg::Matrix mvp = cameraShadow->getViewMatrix() * cameraShadow->getProjectionMatrix();
            ConvexPolyhedron frustum;
            frustum.setToUnitFrustum();
            frustum.transform( osg::Matrix::inverse( mvp ), mvp );

            setDebugPolytope( "shadowCamFrustum", frustum, osg::Vec4(0,0,1,1) );
        }

        {
            osg::Matrix mvp = cameraMain->getViewMatrix() * cameraMain->getProjectionMatrix();
            ConvexPolyhedron frustum;
            frustum.setToUnitFrustum();
            frustum.transform( osg::Matrix::inverse( mvp ), mvp );

            setDebugPolytope( "mainCamFrustum", frustum, osg::Vec4(1,1,1,1) );
        }
#endif
        std::string * filename = getDebugDump( );
        if( filename && !filename->empty() )
        {
            dump( *filename );
            filename->clear();
        }
    }
}