Esempio n. 1
0
inline SceneZoneCullingState::CullingTestResult SceneCullingState::_test( const T& bounds, Iter zoneIter,
                                                                          const PlaneF& nearPlane, const PlaneF& farPlane ) const
{
   // Defer test of near and far plane until we've hit a zone
   // which actually has visible space.  This prevents us from
   // doing near/far tests on objects that were included in the
   // potential render list but aren't actually in any visible
   // zone.
   bool haveTestedNearAndFar = false;

   // Test the culling states of all zones that the object
   // is assigned to.

   for( ; zoneIter.isValid(); ++ zoneIter )
   {
      const SceneZoneCullingState& zoneState = getZoneState( *zoneIter );

      // Skip zone if there are no positive culling volumes.

      if( !zoneState.hasIncluders() )
         continue;

      // If we haven't tested the near and far plane yet, do so
      // now.

      if( !haveTestedNearAndFar )
      {
         // Test near plane.

         PlaneF::Side nearSide = nearPlane.whichSide( bounds );
         if( nearSide == PlaneF::Back )
            return SceneZoneCullingState::CullingTestNegative;

         // Test far plane.

         PlaneF::Side farSide = farPlane.whichSide( bounds );
         if( farSide == PlaneF::Back )
            return SceneZoneCullingState::CullingTestNegative;

         haveTestedNearAndFar = true;
      }

      // If the object's world bounds overlaps any of the volumes
      // for this zone, it's rendered.

      SceneZoneCullingState::CullingTestResult result = zoneState.testVolumes( bounds );

      if( result == SceneZoneCullingState::CullingTestPositiveByInclusion )
         return result;
      else if( result == SceneZoneCullingState::CullingTestPositiveByOcclusion )
         return result;
   }

   return SceneZoneCullingState::CullingTestNegative;
}
ShadowVolumeBSP::SVNode::Side ShadowVolumeBSP::whichSide(SVPoly * poly, const PlaneF & plane) const
{
    bool front = false;
    bool back = false;

    for(U32 i = 0; i < poly->mWindingCount; i++)
    {
        switch(plane.whichSide(poly->mWinding[i]))
        {
        case PlaneF::Front:
            if(back)
                return(SVNode::Split);
            front = true;
            break;

        case PlaneF::Back:
            if(front)
                return(SVNode::Split);
            back = true;
            break;

        default:
            break;
        }
    }

    AssertFatal(!(front && back), "ShadowVolumeBSP::whichSide - failed to classify poly");

    if(!front && !back)
        return(SVNode::On);

    return(front ? SVNode::Front : SVNode::Back);
}
void ShadowVolumeBSP::splitPoly(SVPoly * poly, const PlaneF & plane, SVPoly ** front, SVPoly ** back)
{
    PlaneF::Side sides[SVPoly::MaxWinding];

    U32 i;
    for(i = 0; i < poly->mWindingCount; i++)
        sides[i] = plane.whichSide(poly->mWinding[i]);

    // create the polys
    (*front) = createPoly();
    (*back) = createPoly();

    // copy the info
    (*front)->mWindingCount = (*back)->mWindingCount = 0;
    (*front)->mPlane = (*back)->mPlane = poly->mPlane;
    (*front)->mTarget = (*back)->mTarget = poly->mTarget;
    (*front)->mSurfaceInfo = (*back)->mSurfaceInfo = poly->mSurfaceInfo;
    (*front)->mShadowVolume = (*back)->mShadowVolume = poly->mShadowVolume;

    //
    for(i = 0; i < poly->mWindingCount; i++)
    {
        U32 j = (i+1) % poly->mWindingCount;

        if(sides[i] == PlaneF::On)
        {
            (*front)->mWinding[(*front)->mWindingCount++] = poly->mWinding[i];
            (*back)->mWinding[(*back)->mWindingCount++] = poly->mWinding[i];
        }
        else if(sides[i] == PlaneF::Front)
        {
            (*front)->mWinding[(*front)->mWindingCount++] = poly->mWinding[i];

            if(sides[j] == PlaneF::Back)
            {
                const Point3F & a = poly->mWinding[i];
                const Point3F & b = poly->mWinding[j];

                F32 t = plane.intersect(a, b);
                AssertFatal(t >=0 && t <= 1, "ShadowVolumeBSP::splitPoly - bad plane intersection");

                Point3F pos;
                pos.interpolate(a, b, t);

                //
                (*front)->mWinding[(*front)->mWindingCount++] =
                    (*back)->mWinding[(*back)->mWindingCount++] = pos;
            }
        }
        else if(sides[i] == PlaneF::Back)
        {
            (*back)->mWinding[(*back)->mWindingCount++] = poly->mWinding[i];

            if(sides[j] == PlaneF::Front)
            {
                const Point3F & a = poly->mWinding[i];
                const Point3F & b = poly->mWinding[j];

                F32 t = plane.intersect(a, b);
                AssertFatal(t >=0 && t <= 1, "ShadowVolumeBSP::splitPoly - bad plane intersection");

                Point3F pos;
                pos.interpolate(a, b, t);

                (*front)->mWinding[(*front)->mWindingCount++] =
                    (*back)->mWinding[(*back)->mWindingCount++] = pos;
            }
        }
    }

    AssertFatal((*front)->mWindingCount && (*back)->mWindingCount, "ShadowVolume::split - invalid split");
}