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"); }