예제 #1
0
void MinimalDrawBoundsShadowMap::ViewData::performBoundAnalysis( const osg::Camera& camera )
{
    if( !_projection.valid() )
        return;

    osg::Camera::BufferAttachmentMap & bam 
        = const_cast<osg::Camera&>( camera ).getBufferAttachmentMap();
#if ANALYSIS_DEPTH
    osg::Camera::Attachment & attachment = bam[ osg::Camera::DEPTH_BUFFER ];
#else
    osg::Camera::Attachment & attachment = bam[ osg::Camera::COLOR_BUFFER ];
#endif

    const osg::ref_ptr< osg::Image > image = attachment._image.get();
    if( !image.valid() ) 
        return;

    osg::Matrix m;
    m.invert( *_modellingSpaceToWorldPtr * 
              camera.getViewMatrix() * 
              camera.getProjectionMatrix() );

    m.preMult( osg::Matrix::scale( osg::Vec3( 2.f, 2.f, 2.f ) ) *
               osg::Matrix::translate( osg::Vec3( -1.f, -1.f, -1.f ) ) );

    osg::BoundingBox bb = scanImage( image.get(), m );

    if( getDebugDraw() ) { 
        ConvexPolyhedron p;
        p.setToBoundingBox( bb );
        p.transform( *_modellingSpaceToWorldPtr, 
                 osg::Matrix::inverse( *_modellingSpaceToWorldPtr ) );

        setDebugPolytope( "scan", p,
                      osg::Vec4( 0,0,0,1 ), osg::Vec4( 0,0,0,0.1 ) );
    }

    cutScenePolytope( *_modellingSpaceToWorldPtr, 
                     osg::Matrix::inverse( *_modellingSpaceToWorldPtr ), bb );

    frameShadowCastingCamera( _mainCamera.get(), _camera.get() );

    _projection->set( _camera->getProjectionMatrix( ) );

    BaseClass::ViewData::_texgen->setPlanesFromMatrix(
            _camera->getProjectionMatrix() *
            osg::Matrix::translate(1.0,1.0,1.0) *
            osg::Matrix::scale(0.5,0.5,0.5) );

    updateDebugGeometry( _mainCamera.get(),  _camera.get() );
}
예제 #2
0
//----------------------------------------------------------------------------
ConvexClipper::ConvexClipper (const ConvexPolyhedron& rkPoly, Real fEpsilon)
{
    m_fEpsilon = fEpsilon;

    const vector<Vector3>& rakPoint = rkPoly.GetPoints();
    int iVQuantity = rkPoly.GetVQuantity();
    m_akVertex.resize(iVQuantity);
    for (int iV = 0; iV < iVQuantity; iV++)
        m_akVertex[iV].m_kPoint = rakPoint[iV];

    int iEQuantity = rkPoly.GetEQuantity();
    m_akEdge.resize(iEQuantity);
    for (int iE = 0; iE < iEQuantity; iE++)
    {
        const MTEdge& rkE = rkPoly.GetEdge(iE);
        for (int i = 0; i < 2; i++)
        {
            m_akEdge[iE].m_aiVertex[i] = rkPoly.GetVLabel(rkE.GetVertex(i));
            m_akEdge[iE].m_aiFace[i] = rkE.GetTriangle(i);
        }
    }

    int iTQuantity = rkPoly.GetTQuantity();
    m_akFace.resize(iTQuantity);
    for (int iT = 0; iT < iTQuantity; iT++)
    {
        m_akFace[iT].m_kPlane = rkPoly.GetPlane(iT);

        const MTTriangle& rkT = rkPoly.GetTriangle(iT);
        for (int i = 0; i < 3; i++)
            m_akFace[iT].m_akEdge.insert(rkT.GetEdge(i));
    }
}
//----------------------------------------------------------------------------
bool ConvexPolyhedron::FindIntersection (const ConvexPolyhedron& rkPoly,
        ConvexPolyhedron& rkIntr) const
{
    ConvexClipper kClipper(*this);

    const vector<Plane>& rakPlane = rkPoly.GetPlanes();
    for (int i = 0; i < (int)rakPlane.size(); i++)
    {
        if ( kClipper.Clip(rakPlane[i]) == Plane::NEGATIVE_SIDE )
            return false;
    }

    kClipper.Convert(rkIntr);
    return true;
}
예제 #4
0
ConvexClipper<Real>::ConvexClipper (const ConvexPolyhedron<Real>& polyhedron,
    Real epsilon)
    :
    mEpsilon(epsilon)
{
    const std::vector<Vector3<Real> >& points = polyhedron.GetPoints();
    int numVertices = polyhedron.GetNumVertices();
    mVertices.resize(numVertices);
    for (int v = 0; v < numVertices; ++v)
    {
        mVertices[v].Point = points[v];
    }

    int numEdges = polyhedron.GetNumEdges();
    mEdges.resize(numEdges);
    for (int e = 0; e < numEdges; ++e)
    {
        const MTEdge& edge = polyhedron.GetEdge(e);
        for (int i = 0; i < 2; ++i)
        {
            mEdges[e].Vertex[i] = polyhedron.GetVLabel(edge.GetVertex(i));
            mEdges[e].Face[i] = edge.GetTriangle(i);
        }
    }

    int numTriangles = polyhedron.GetNumTriangles();
    mFaces.resize(numTriangles);
    for (int t = 0; t < numTriangles; ++t)
    {
        mFaces[t].Plane = polyhedron.GetPlane(t);
        const MTTriangle& triangle = polyhedron.GetTriangle(t);
        for (int i = 0; i < 3; ++i)
        {
            mFaces[t].Edges.insert(triangle.GetEdge(i));
        }
    }
}
예제 #5
0
void ConvexClipper<Real>::Convert (ConvexPolyhedron<Real>& polyhedron)
{
    // Get visible vertices.
    int numVertices = (int)mVertices.size();
    std::vector<Vector3<Real> > points;
    int* vMap = new1<int>(numVertices);
    memset(vMap, 0xFF, numVertices*sizeof(int));
    for (int v = 0; v < numVertices; ++v)
    {
        const Vertex& vertex = mVertices[v];
        if (vertex.Visible)
        {
            vMap[v] = (int)points.size();
            points.push_back(vertex.Point);
        }
    }

    std::vector<int> indices;
    std::vector<Plane3<Real> > planes;
    GetTriangles(indices, planes);

    // Reorder the indices.
    for (int c = 0; c < (int)indices.size(); ++c)
    {
        int oldC = indices[c];
        assertion(0 <= oldC && oldC < numVertices, "Index out of range.\n");
        int newC = vMap[oldC];
        assertion(0 <= newC && newC < (int)points.size(),
            "Index out of range.\n");
        indices[c] = newC;
    }

    delete1(vMap);

    polyhedron.Create(points, indices, planes);
}
예제 #6
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();
}
//----------------------------------------------------------------------------
void ConvexPolyhedron::CreateEggShape (const Vector3& rkCenter, Real fX0,
                                       Real fX1, Real fY0, Real fY1, Real fZ0, Real fZ1, int iMaxSteps,
                                       ConvexPolyhedron& rkEgg)
{
    assert( fX0 > 0.0f && fX1 > 0.0f );
    assert( fY0 > 0.0f && fY1 > 0.0f );
    assert( fZ0 > 0.0f && fZ1 > 0.0f );
    assert( iMaxSteps >= 0 );

    // Start with an octahedron whose 6 vertices are (-x0,0,0), (x1,0,0),
    // (0,-y0,0), (0,y1,0), (0,0,-z0), (0,0,z1).  The center point will be
    // added later.
    vector<Vector3> akPoint(6);
    akPoint[0] = Vector3(-fX0,0.0f,0.0f);
    akPoint[1] = Vector3(fX1,0.0f,0.0f);
    akPoint[2] = Vector3(0.0f,-fY0,0.0f);
    akPoint[3] = Vector3(0.0f,fY1,0.0f);
    akPoint[4] = Vector3(0.0f,0.0f,-fZ0);
    akPoint[5] = Vector3(0.0f,0.0f,fZ1);

    vector<int> aiConnect(24);
    aiConnect[ 0] = 1;
    aiConnect[ 1] = 3;
    aiConnect[ 2] = 5;
    aiConnect[ 3] = 3;
    aiConnect[ 4] = 0;
    aiConnect[ 5] = 5;
    aiConnect[ 6] = 0;
    aiConnect[ 7] = 2;
    aiConnect[ 8] = 5;
    aiConnect[ 9] = 2;
    aiConnect[10] = 1;
    aiConnect[11] = 5;
    aiConnect[12] = 3;
    aiConnect[13] = 1;
    aiConnect[14] = 4;
    aiConnect[15] = 0;
    aiConnect[16] = 3;
    aiConnect[17] = 4;
    aiConnect[18] = 2;
    aiConnect[19] = 0;
    aiConnect[20] = 4;
    aiConnect[21] = 1;
    aiConnect[22] = 2;
    aiConnect[23] = 4;

    rkEgg.InitialELabel() = 0;
    rkEgg.Create(akPoint,aiConnect);

    // Subdivide the triangles.  The midpoints of the edges are computed.
    // The triangle is replaced by four sub triangles using the original 3
    // vertices and the 3 new edge midpoints.

    int i;
    for (int iStep = 1; iStep <= iMaxSteps; iStep++)
    {
        int iVQuantity = rkEgg.GetVQuantity();
        int iEQuantity = rkEgg.GetEQuantity();
        int iTQuantity = rkEgg.GetTQuantity();

        // compute lifted edge midpoints
        for (i = 0; i < iEQuantity; i++)
        {
            // get edge
            const MTEdge& rkE = rkEgg.GetEdge(i);
            int iV0 = rkEgg.GetVLabel(rkE.GetVertex(0));
            int iV1 = rkEgg.GetVLabel(rkE.GetVertex(1));

            // compute "lifted" centroid to points
            Vector3 kCen = rkEgg.Point(iV0)+rkEgg.Point(iV1);
            Real fXR = (kCen.x > 0.0f ? kCen.x/fX1 : kCen.x/fX0);
            Real fYR = (kCen.y > 0.0f ? kCen.y/fY1 : kCen.y/fY0);
            Real fZR = (kCen.z > 0.0f ? kCen.z/fZ1 : kCen.z/fZ0);
            kCen *= Math::InvSqrt(fXR*fXR+fYR*fYR+fZR*fZR);

            // Add the point to the array.  Store the point index in the edge
            // label for support in adding new triangles.
            rkEgg.ELabel(i) = iVQuantity++;
            rkEgg.AddPoint(kCen);
        }

        // Add the new triangles and remove the old triangle.  The removal
        // in slot i will cause the last added triangle to be moved to that
        // slot.  This side effect will not interfere with the iteration
        // and removal of the triangles.
        for (i = 0; i < iTQuantity; i++)
        {
            const MTTriangle& rkT = rkEgg.GetTriangle(i);
            int iV0 = rkEgg.GetVLabel(rkT.GetVertex(0));
            int iV1 = rkEgg.GetVLabel(rkT.GetVertex(1));
            int iV2 = rkEgg.GetVLabel(rkT.GetVertex(2));
            int iV01 = rkEgg.GetELabel(rkT.GetEdge(0));
            int iV12 = rkEgg.GetELabel(rkT.GetEdge(1));
            int iV20 = rkEgg.GetELabel(rkT.GetEdge(2));
            rkEgg.Insert(iV0,iV01,iV20);
            rkEgg.Insert(iV01,iV1,iV12);
            rkEgg.Insert(iV20,iV12,iV2);
            rkEgg.Insert(iV01,iV12,iV20);
            rkEgg.Remove(iV0,iV1,iV2);
        }
    }

    // add center
    for (i = 0; i < (int)rkEgg.m_akPoint.size(); i++)
        rkEgg.m_akPoint[i] += rkCenter;

    rkEgg.UpdatePlanes();
}
예제 #8
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();
        }
    }
}