SceneCullingState with culling and camera frustum

- Fix for issue https://github.com/GarageGames/Torque3D/issues/525  This
fix takes into account the skewed view into the world when you have a
projection offset and the ability to see further into the scene at the
edges opposite to the offset.
- SceneCullingState now has two frustum rather than one: a culling
frustum and camera frustum.
- The camera frustum should be referenced when you need the projection
matrix or don't want a skewed frustum.
- The culling frustum should be referenced during any scene culling or
when determining what dynamic geometry to render.  It currently skews
itself to take into account any projection offset (automatically
calculated in SceneCullingState constructor).
- When there is no projection offset, the camera frustum and culling
frustum are the same.  This usually means any time when not using the
Oculus Rift.
This commit is contained in:
DavidWyand-GG 2013-11-07 15:07:16 -05:00
parent 9af13248cf
commit 91e542b8ec
22 changed files with 161 additions and 47 deletions

View file

@ -68,17 +68,21 @@ SceneCullingState::SceneCullingState( SceneManager* sceneManager, const SceneCam
mZoneVisibilityFlags.setSize( numZones );
mZoneVisibilityFlags.clear();
// Culling frustum
mCullingFrustum = mCameraState.getFrustum();
mCullingFrustum.bakeProjectionOffset();
// Construct the root culling volume from
// the camera's view frustum. Omit the frustum's
// the culling frustum. Omit the frustum's
// near and far plane so we don't test it repeatedly.
const Frustum& frustum = mCameraState.getFrustum();
PlaneF* planes = allocateData< PlaneF >( 4 );
planes[ 0 ] = frustum.getPlanes()[ Frustum::PlaneLeft ];
planes[ 1 ] = frustum.getPlanes()[ Frustum::PlaneRight ];
planes[ 2 ] = frustum.getPlanes()[ Frustum::PlaneTop];
planes[ 3 ] = frustum.getPlanes()[ Frustum::PlaneBottom ];
planes[ 0 ] = mCullingFrustum.getPlanes()[ Frustum::PlaneLeft ];
planes[ 1 ] = mCullingFrustum.getPlanes()[ Frustum::PlaneRight ];
planes[ 2 ] = mCullingFrustum.getPlanes()[ Frustum::PlaneTop];
planes[ 3 ] = mCullingFrustum.getPlanes()[ Frustum::PlaneBottom ];
mRootVolume = SceneCullingVolume(
SceneCullingVolume::Includer,
@ -219,7 +223,7 @@ bool SceneCullingState::createCullingVolume( const Point3F* vertices, U32 numVer
{
const Point3F& viewPos = getCameraState().getViewPosition();
const Point3F& viewDir = getCameraState().getViewDirection();
const bool isOrtho = getFrustum().isOrtho();
const bool isOrtho = getCullingFrustum().isOrtho();
//TODO: check if we need to handle penetration of the near plane for occluders specially
@ -440,8 +444,8 @@ bool SceneCullingState::createCullingVolume( const Point3F* vertices, U32 numVer
if( type == SceneCullingVolume::Occluder )
{
const F32 widthEstimatePercentage = widthEstimate / getFrustum().getWidth();
const F32 heightEstimatePercentage = heightEstimate / getFrustum().getHeight();
const F32 widthEstimatePercentage = widthEstimate / getCullingFrustum().getWidth();
const F32 heightEstimatePercentage = heightEstimate / getCullingFrustum().getHeight();
if( widthEstimatePercentage < smOccluderMinWidthPercentage ||
heightEstimatePercentage < smOccluderMinHeightPercentage )
@ -614,7 +618,7 @@ inline SceneZoneCullingState::CullingTestResult SceneCullingState::_test( const
if( disableZoneCulling() )
{
if( !OCCLUDERS_ONLY && !getFrustum().isCulled( bounds ) )
if( !OCCLUDERS_ONLY && !getCullingFrustum().isCulled( bounds ) )
return SceneZoneCullingState::CullingTestPositiveByInclusion;
return SceneZoneCullingState::CullingTestNegative;
@ -631,7 +635,7 @@ inline SceneZoneCullingState::CullingTestResult SceneCullingState::_test( const
}
else
{
const PlaneF* frustumPlanes = getFrustum().getPlanes();
const PlaneF* frustumPlanes = getCullingFrustum().getPlanes();
return _test(
bounds,
@ -715,8 +719,8 @@ U32 SceneCullingState::cullObjects( SceneObject** objects, U32 numObjects, U32 c
// We test near and far planes separately in order to not do the tests
// repeatedly, so fetch the planes now.
const PlaneF& nearPlane = getFrustum().getPlanes()[ Frustum::PlaneNear ];
const PlaneF& farPlane = getFrustum().getPlanes()[ Frustum::PlaneFar ];
const PlaneF& nearPlane = getCullingFrustum().getPlanes()[ Frustum::PlaneNear ];
const PlaneF& farPlane = getCullingFrustum().getPlanes()[ Frustum::PlaneFar ];
for( U32 i = 0; i < numObjects; ++ i )
{
@ -766,7 +770,7 @@ U32 SceneCullingState::cullObjects( SceneObject** objects, U32 numObjects, U32 c
( object->getTypeMask() & CULLING_EXCLUDE_TYPEMASK ) ||
disableZoneCulling() )
{
isCulled = getFrustum().isCulled( object->getWorldBox() );
isCulled = getCullingFrustum().isCulled( object->getWorldBox() );
}
// Go through the zones that the object is assigned to and
@ -881,8 +885,8 @@ void SceneCullingState::debugRenderCullingVolumes() const
const ColorI occluderColor( 255, 0, 0, 255 );
const ColorI includerColor( 0, 255, 0, 255 );
const PlaneF& nearPlane = getFrustum().getPlanes()[ Frustum::PlaneNear ];
const PlaneF& farPlane = getFrustum().getPlanes()[ Frustum::PlaneFar ];
const PlaneF& nearPlane = getCullingFrustum().getPlanes()[ Frustum::PlaneNear ];
const PlaneF& farPlane = getCullingFrustum().getPlanes()[ Frustum::PlaneFar ];
DebugDrawer* drawer = DebugDrawer::get();
const SceneZoneSpaceManager* zoneManager = mSceneManager->getZoneManager();

View file

@ -100,9 +100,12 @@ class SceneCullingState
/// The viewing state that defines how the scene is being viewed.
SceneCameraState mCameraState;
/// The root culling volume corresponding to the camera frustum.
/// The root culling volume corresponding to the culling frustum.
SceneCullingVolume mRootVolume;
/// The root culling frustum, which may be different from the camera frustum
Frustum mCullingFrustum;
/// Occluders that have been added to this render state. Adding an occluder does not
/// necessarily result in an occluder volume being added. To not repeatedly try to
/// process the same occluder object, all objects that are added are recorded here.
@ -136,7 +139,10 @@ class SceneCullingState
SceneManager* getSceneManager() const { return mSceneManager; }
/// Return the root frustum which is used to set up scene visibility.
const Frustum& getFrustum() const { return getCameraState().getFrustum(); }
const Frustum& getCullingFrustum() const { return mCullingFrustum; }
/// Return the root frustum which is used to set up scene visibility.
const Frustum& getCameraFrustum() const { return getCameraState().getFrustum(); }
/// Return the viewing state that defines how the scene is being viewed.
const SceneCameraState& getCameraState() const { return mCameraState; }

View file

@ -420,7 +420,7 @@ void CubeReflector::updateFace( const ReflectParams &params, U32 faceidx )
reflectRenderState.disableAdvancedLightingBins(true);
// render scene
LIGHTMGR->registerGlobalLights( &reflectRenderState.getFrustum(), false );
LIGHTMGR->registerGlobalLights( &reflectRenderState.getCullingFrustum(), false );
gClientSceneGraph->renderSceneNoLights( &reflectRenderState, mDesc->objectTypeMask );
LIGHTMGR->unregisterAllLights();

View file

@ -191,7 +191,7 @@ void SceneManager::renderScene( SceneRenderState* renderState, U32 objectMask, S
// Get the lights for rendering the scene.
PROFILE_START( SceneGraph_registerLights );
LIGHTMGR->registerGlobalLights( &renderState->getFrustum(), false );
LIGHTMGR->registerGlobalLights( &renderState->getCullingFrustum(), false );
PROFILE_END();
// If its a diffuse pass, update the current ambient light level.
@ -404,7 +404,7 @@ void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZ
// the opportunity to render editor visualizations even if
// they are otherwise not in view.
if( !state->getFrustum().getBounds().isOverlapped( state->getRenderArea() ) )
if( !state->getCullingFrustum().getBounds().isOverlapped( state->getRenderArea() ) )
{
// This handles fringe cases like flying backwards into a zone where you
// end up pretty much standing on a zone border and looking directly into
@ -415,7 +415,7 @@ void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZ
return;
}
Box3F queryBox = state->getFrustum().getBounds();
Box3F queryBox = state->getCullingFrustum().getBounds();
if( !gEditingMission )
{
queryBox.minExtents.setMax( state->getRenderArea().minExtents );

View file

@ -145,8 +145,11 @@ class SceneRenderState
const SceneCullingState& getCullingState() const { return mCullingState; }
SceneCullingState& getCullingState() { return mCullingState; }
/// Returns the root frustum.
const Frustum& getFrustum() const { return getCullingState().getFrustum(); }
/// Returns the root culling frustum.
const Frustum& getCullingFrustum() const { return getCullingState().getCullingFrustum(); }
/// Returns the root camera frustum.
const Frustum& getCameraFrustum() const { return getCullingState().getCameraFrustum(); }
/// @}
@ -262,10 +265,10 @@ class SceneRenderState
const MatrixF& getCameraTransform() const { return getCullingState().getCameraState().getViewWorldMatrix(); }
/// Returns the minimum distance something must be from the camera to not be culled.
F32 getNearPlane() const { return getFrustum().getNearDist(); }
F32 getNearPlane() const { return getCullingFrustum().getNearDist(); }
/// Returns the maximum distance something can be from the camera to not be culled.
F32 getFarPlane() const { return getFrustum().getFarDist(); }
F32 getFarPlane() const { return getCullingFrustum().getFarDist(); }
/// Returns the camera vector normalized to 1 / far distance.
const Point3F& getVectorEye() const { return mVectorEye; }