From 91e542b8ec4e69df8270dbea69d2631516033311 Mon Sep 17 00:00:00 2001 From: DavidWyand-GG Date: Thu, 7 Nov 2013 15:07:16 -0500 Subject: [PATCH] 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. --- Engine/source/T3D/decal/decalManager.cpp | 4 +- Engine/source/T3D/fx/fxFoliageReplicator.cpp | 2 +- Engine/source/T3D/fx/groundCover.cpp | 2 +- Engine/source/T3D/groundPlane.cpp | 2 +- Engine/source/T3D/lightFlareData.cpp | 4 +- Engine/source/T3D/tsStatic.cpp | 2 +- Engine/source/environment/decalRoad.cpp | 2 +- Engine/source/environment/scatterSky.cpp | 2 +- Engine/source/environment/waterPlane.cpp | 4 +- Engine/source/forest/forestRender.cpp | 2 +- .../advanced/advancedLightBinManager.cpp | 2 +- .../lighting/common/projectedShadow.cpp | 2 +- .../lighting/shadowMap/pssmLightShadowMap.cpp | 4 +- .../shadowMap/singleLightShadowMap.cpp | 2 +- Engine/source/math/util/frustum.cpp | 94 +++++++++++++++++++ Engine/source/math/util/frustum.h | 7 ++ Engine/source/postFx/postEffect.cpp | 6 +- .../scene/culling/sceneCullingState.cpp | 36 +++---- .../source/scene/culling/sceneCullingState.h | 10 +- Engine/source/scene/reflector.cpp | 2 +- Engine/source/scene/sceneManager.cpp | 6 +- Engine/source/scene/sceneRenderState.h | 11 ++- 22 files changed, 161 insertions(+), 47 deletions(-) diff --git a/Engine/source/T3D/decal/decalManager.cpp b/Engine/source/T3D/decal/decalManager.cpp index 153209933..a39e4bf8d 100644 --- a/Engine/source/T3D/decal/decalManager.cpp +++ b/Engine/source/T3D/decal/decalManager.cpp @@ -1004,7 +1004,7 @@ void DecalManager::prepRenderImage( SceneRenderState* state ) PROFILE_START( DecalManager_RenderDecals_SphereTreeCull ); - const Frustum& rootFrustum = state->getFrustum(); + const Frustum& rootFrustum = state->getCameraFrustum(); // Populate vector of decal instances to be rendered with all // decals from visible decal spheres. @@ -1448,7 +1448,7 @@ void DecalManager::_renderDecalSpheres( ObjectRenderInst* ri, SceneRenderState* DecalSphere *decalSphere = grid[i]; const SphereF &worldSphere = decalSphere->mWorldSphere; - if( state->getFrustum().isCulled( worldSphere ) ) + if( state->getCullingFrustum().isCulled( worldSphere ) ) continue; drawUtil->drawSphere( desc, worldSphere.radius, worldSphere.center, sphereColor ); diff --git a/Engine/source/T3D/fx/fxFoliageReplicator.cpp b/Engine/source/T3D/fx/fxFoliageReplicator.cpp index 04b6c8976..7e88b174f 100644 --- a/Engine/source/T3D/fx/fxFoliageReplicator.cpp +++ b/Engine/source/T3D/fx/fxFoliageReplicator.cpp @@ -146,7 +146,7 @@ void fxFoliageRenderList::SetupClipPlanes( SceneRenderState* state, const F32 fa const F32 nearPlane = state->getNearPlane(); const F32 farPlane = farClipPlane; - const Frustum& frustum = state->getFrustum(); + const Frustum& frustum = state->getCullingFrustum(); // [rene, 23-Feb-11] Why isn't this preserving the ortho state of the original frustum? diff --git a/Engine/source/T3D/fx/groundCover.cpp b/Engine/source/T3D/fx/groundCover.cpp index 1d0c2f9fd..5317f139e 100644 --- a/Engine/source/T3D/fx/groundCover.cpp +++ b/Engine/source/T3D/fx/groundCover.cpp @@ -1539,7 +1539,7 @@ void GroundCover::prepRenderImage( SceneRenderState *state ) // Setup the frustum culler. if ( ( mCuller.getPosition().isZero() || !mDebugLockFrustum ) && !state->isShadowPass() ) - mCuller = state->getFrustum(); + mCuller = state->getCullingFrustum(); // Update the cells, but only during the diffuse pass. // We don't want cell generation to thrash when the reflection camera diff --git a/Engine/source/T3D/groundPlane.cpp b/Engine/source/T3D/groundPlane.cpp index d3d27d5cb..b188a7d39 100644 --- a/Engine/source/T3D/groundPlane.cpp +++ b/Engine/source/T3D/groundPlane.cpp @@ -352,7 +352,7 @@ void GroundPlane::prepRenderImage( SceneRenderState* state ) PROFILE_SCOPE( GroundPlane_prepRender ); // Update the geometry. - createGeometry( state->getFrustum() ); + createGeometry( state->getCullingFrustum() ); if( mVertexBuffer.isNull() ) return; diff --git a/Engine/source/T3D/lightFlareData.cpp b/Engine/source/T3D/lightFlareData.cpp index 5a3e0e322..8cbad24fc 100644 --- a/Engine/source/T3D/lightFlareData.cpp +++ b/Engine/source/T3D/lightFlareData.cpp @@ -279,7 +279,7 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt const Point3F &lightPos = flareState->lightMat.getPosition(); const RectI &viewport = GFX->getViewport(); MatrixF projMatrix; - state->getFrustum().getProjectionMatrix(&projMatrix); + state->getCameraFrustum().getProjectionMatrix(&projMatrix); if( state->isReflectPass() ) projMatrix = state->getSceneManager()->getNonClipProjection(); bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix ); @@ -465,7 +465,7 @@ void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flare // Take any projection offset into account so that the point where the flare's // elements converge is at the 'eye' point rather than the center of the viewport. - const Point2F& projOffset = state->getFrustum().getProjectionOffset(); + const Point2F& projOffset = state->getCameraFrustum().getProjectionOffset(); Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) ); const F32 flareLength = flareVec.len(); if ( flareLength > 0.0f ) diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index b1315cd2a..f2e666c4f 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -525,7 +525,7 @@ void TSStatic::prepRenderImage( SceneRenderState* state ) Frustum culler; if ( mMeshCulling ) { - culler = state->getFrustum(); + culler = state->getCullingFrustum(); MatrixF xfm( true ); xfm.scale( Point3F::One / getScale() ); xfm.mul( getRenderWorldTransform() ); diff --git a/Engine/source/environment/decalRoad.cpp b/Engine/source/environment/decalRoad.cpp index 71d29be96..7bd240095 100644 --- a/Engine/source/environment/decalRoad.cpp +++ b/Engine/source/environment/decalRoad.cpp @@ -721,7 +721,7 @@ void DecalRoad::prepRenderImage( SceneRenderState* state ) if ( !smShowRoad && smEditorOpen ) return; - const Frustum &frustum = state->getFrustum(); + const Frustum &frustum = state->getCameraFrustum(); MeshRenderInst coreRI; coreRI.clear(); diff --git a/Engine/source/environment/scatterSky.cpp b/Engine/source/environment/scatterSky.cpp index cebc8b9b2..7fdf25296 100644 --- a/Engine/source/environment/scatterSky.cpp +++ b/Engine/source/environment/scatterSky.cpp @@ -930,7 +930,7 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat Point3F camPos( 0, 0, smViewerHeight ); Point4F miscParams( camPos.z, camPos.z * camPos.z, mScale, mScale / mRayleighScaleDepth ); - Frustum frust = state->getFrustum(); + Frustum frust = state->getCameraFrustum(); frust.setFarDist( smEarthRadius + smAtmosphereRadius ); MatrixF proj( true ); frust.getProjectionMatrix( &proj ); diff --git a/Engine/source/environment/waterPlane.cpp b/Engine/source/environment/waterPlane.cpp index c0158a61f..eab66a466 100644 --- a/Engine/source/environment/waterPlane.cpp +++ b/Engine/source/environment/waterPlane.cpp @@ -173,7 +173,7 @@ void WaterPlane::unpackUpdate(NetConnection* con, BitStream* stream) void WaterPlane::setupVBIB( SceneRenderState *state ) { - const Frustum &frustum = state->getFrustum(); + const Frustum &frustum = state->getCullingFrustum(); // Water base-color, assigned as color for all verts. const GFXVertexColor vertCol(mWaterFogData.color); @@ -708,7 +708,7 @@ void WaterPlane::prepRenderImage( SceneRenderState *state ) mMatrixSet->setSceneView(GFX->getWorldMatrix()); - const Frustum &frustum = state->getFrustum(); + const Frustum &frustum = state->getCameraFrustum(); if ( mPrimBuff.isNull() || mGenerateVB || diff --git a/Engine/source/forest/forestRender.cpp b/Engine/source/forest/forestRender.cpp index 0c7a3fb91..3fa2b3047 100644 --- a/Engine/source/forest/forestRender.cpp +++ b/Engine/source/forest/forestRender.cpp @@ -110,7 +110,7 @@ void Forest::prepRenderImage( SceneRenderState *state ) // the forest, so pass down a LightQuery for it. LightQuery lightQuery; rdata.setLightQuery( &lightQuery ); - Frustum culler = state->getFrustum(); + Frustum culler = state->getCullingFrustum(); // Adjust the far distance if the cull scale has changed. if ( !mIsEqual( cullScale, 1.0f ) ) diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index 069f0e762..d8620e856 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -444,7 +444,7 @@ void AdvancedLightBinManager::_deleteLightMaterials() void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *state ) { PROFILE_SCOPE( AdvancedLightBinManager_SetupPerFrameParameters ); - const Frustum &frustum = state->getFrustum(); + const Frustum &frustum = state->getCameraFrustum(); MatrixF invCam( frustum.getTransform() ); invCam.inverse(); diff --git a/Engine/source/lighting/common/projectedShadow.cpp b/Engine/source/lighting/common/projectedShadow.cpp index de3a31f8f..ed4a7b903 100644 --- a/Engine/source/lighting/common/projectedShadow.cpp +++ b/Engine/source/lighting/common/projectedShadow.cpp @@ -324,7 +324,7 @@ bool ProjectedShadow::_updateDecal( const SceneRenderState *state ) bool shouldClip = lightDirChanged || hasMoved || hasScaled; // Now, check and see if the object is visible. - const Frustum &frust = state->getFrustum(); + const Frustum &frust = state->getCullingFrustum(); if ( frust.isCulled( SphereF( mDecalInstance->mPosition, mDecalInstance->mSize * mDecalInstance->mSize ) ) && !shouldClip ) return false; diff --git a/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp b/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp index e8bf8df31..71a4fe585 100644 --- a/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp +++ b/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp @@ -207,7 +207,7 @@ void PSSMLightShadowMap::_render( RenderPassManager* renderPass, _setNumSplits( params->numSplits, texSize ); mLogWeight = params->logWeight; - Frustum fullFrustum( diffuseState->getFrustum() ); + Frustum fullFrustum( diffuseState->getCameraFrustum() ); fullFrustum.cropNearFar(fullFrustum.getNearDist(), params->shadowDistance); GFXFrustumSaver frustSaver; @@ -223,7 +223,7 @@ void PSSMLightShadowMap::_render( RenderPassManager* renderPass, // Calculate our standard light matrices MatrixF lightMatrix; - calcLightMatrices( lightMatrix, diffuseState->getFrustum() ); + calcLightMatrices( lightMatrix, diffuseState->getCameraFrustum() ); lightMatrix.inverse(); MatrixF lightViewProj = GFX->getProjectionMatrix() * lightMatrix; diff --git a/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp b/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp index 3d13f245c..e8dc240a2 100644 --- a/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp +++ b/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp @@ -67,7 +67,7 @@ void SingleLightShadowMap::_render( RenderPassManager* renderPass, GFXTransformSaver saver; MatrixF lightMatrix; - calcLightMatrices( lightMatrix, diffuseState->getFrustum() ); + calcLightMatrices( lightMatrix, diffuseState->getCameraFrustum() ); lightMatrix.inverse(); GFX->setWorldMatrix(lightMatrix); diff --git a/Engine/source/math/util/frustum.cpp b/Engine/source/math/util/frustum.cpp index 7cff16e4c..f95814b3f 100644 --- a/Engine/source/math/util/frustum.cpp +++ b/Engine/source/math/util/frustum.cpp @@ -228,6 +228,100 @@ void Frustum::cropNearFar(F32 newNearDist, F32 newFarDist) //----------------------------------------------------------------------------- +bool Frustum::bakeProjectionOffset() +{ + // Nothing to bake if ortho + if( mIsOrtho ) + return false; + + // Nothing to bake if no offset + if( mProjectionOffset.isZero() ) + return false; + + // Near plane points in camera space + Point3F np[4]; + np[0].set( mNearLeft, mNearDist, mNearTop ); // NearTopLeft + np[1].set( mNearRight, mNearDist, mNearTop ); // NearTopRight + np[2].set( mNearLeft, mNearDist, mNearBottom ); // NearBottomLeft + np[3].set( mNearRight, mNearDist, mNearBottom ); // NearBottomRight + + // Generate the near plane + PlaneF nearPlane( np[0], np[1], np[3] ); + + // Far plane points in camera space + const F32 farOverNear = mFarDist / mNearDist; + Point3F fp0( mNearLeft * farOverNear, mFarDist, mNearTop * farOverNear ); // FarTopLeft + Point3F fp1( mNearRight * farOverNear, mFarDist, mNearTop * farOverNear ); // FarTopRight + Point3F fp2( mNearLeft * farOverNear, mFarDist, mNearBottom * farOverNear ); // FarBottomLeft + Point3F fp3( mNearRight * farOverNear, mFarDist, mNearBottom * farOverNear ); // FarBottomRight + + // Generate the far plane + PlaneF farPlane( fp0, fp1, fp3 ); + + // The offset camera point + Point3F offsetCamera( mProjectionOffset.x, 0.0f, mProjectionOffset.y ); + + // The near plane point we'll be using for our calculations below + U32 nIndex = 0; + if( mProjectionOffset.x < 0.0 ) + { + // Offset to the left so we'll need to use the near plane point on the right + nIndex = 1; + } + if( mProjectionOffset.y > 0.0 ) + { + // Offset to the top so we'll need to use the near plane point at the bottom + nIndex += 2; + } + + // Begin by calculating the offset point on the far plane as it goes + // from the offset camera to the edge of the near plane. + Point3F farPoint; + Point3F fdir = np[nIndex] - offsetCamera; + fdir.normalize(); + if( farPlane.intersect(offsetCamera, fdir, &farPoint) ) + { + // Calculate the new near plane edge from the non-offset camera position + // to the far plane point from above. + Point3F nearPoint; + Point3F ndir = farPoint; + ndir.normalize(); + if( nearPlane.intersect( Point3F::Zero, ndir, &nearPoint) ) + { + // Handle a x offset + if( mProjectionOffset.x < 0.0 ) + { + // The new near plane right side + mNearRight = nearPoint.x; + } + else if( mProjectionOffset.x > 0.0 ) + { + // The new near plane left side + mNearLeft = nearPoint.x; + } + + // Handle a y offset + if( mProjectionOffset.y < 0.0 ) + { + // The new near plane top side + mNearTop = nearPoint.y; + } + else if( mProjectionOffset.y > 0.0 ) + { + // The new near plane bottom side + mNearBottom = nearPoint.y; + } + } + } + + mDirty = true; + + // Indicate that we've modified the frustum + return true; +} + +//----------------------------------------------------------------------------- + void FrustumData::_update() const { if( !mDirty ) diff --git a/Engine/source/math/util/frustum.h b/Engine/source/math/util/frustum.h index 50b935985..0f71063d9 100644 --- a/Engine/source/math/util/frustum.h +++ b/Engine/source/math/util/frustum.h @@ -412,6 +412,9 @@ class Frustum : public PolyhedronImpl< FrustumData > /// points typically used for early rejection. const Box3F& getBounds() const { _update(); return mBounds; } + // Does the frustum have a projection offset? + bool hasProjectionOffset() const { return !mProjectionOffset.isZero(); } + /// Get the offset used when calculating the projection matrix const Point2F& getProjectionOffset() const { return mProjectionOffset; } @@ -424,6 +427,10 @@ class Frustum : public PolyhedronImpl< FrustumData > /// Clear any offset used when calculating the projection matrix void clearProjectionOffset() { mProjectionOffset.zero(); mProjectionOffsetMatrix.identity(); } + /// Enlarges the frustum to contain the planes generated by a project offset, if any. + /// Used by scene culling to ensure that all object are contained within the asymetrical frustum. + bool bakeProjectionOffset(); + /// Generates a projection matrix from the frustum. void getProjectionMatrix( MatrixF *proj, bool gfxRotate=true ) const; diff --git a/Engine/source/postFx/postEffect.cpp b/Engine/source/postFx/postEffect.cpp index 9a0e9e4e4..aff1e6f2c 100644 --- a/Engine/source/postFx/postEffect.cpp +++ b/Engine/source/postFx/postEffect.cpp @@ -719,7 +719,7 @@ void PostEffect::_setupConstants( const SceneRenderState *state ) mShaderConsts->setSafe( mNearFarSC, Point2F( state->getNearPlane(), state->getFarPlane() ) ); mShaderConsts->setSafe( mInvNearFarSC, Point2F( 1.0f / state->getNearPlane(), 1.0f / state->getFarPlane() ) ); mShaderConsts->setSafe( mWorldToScreenScaleSC, state->getWorldToScreenScale() ); - mShaderConsts->setSafe( mProjectionOffsetSC, state->getFrustum().getProjectionOffset() ); + mShaderConsts->setSafe( mProjectionOffsetSC, state->getCameraFrustum().getProjectionOffset() ); mShaderConsts->setSafe( mFogColorSC, state->getSceneManager()->getFogData().color ); if ( mWaterColorSC->isValid() ) @@ -750,7 +750,7 @@ void PostEffect::_setupConstants( const SceneRenderState *state ) { // Grab our projection matrix // from the frustum. - Frustum frust = state->getFrustum(); + Frustum frust = state->getCameraFrustum(); MatrixF proj( true ); frust.getProjectionMatrix( &proj ); @@ -1219,7 +1219,7 @@ void PostEffect::process( const SceneRenderState *state, Frustum frustum; if ( state ) - frustum = state->getFrustum(); + frustum = state->getCameraFrustum(); else { // If we don't have a scene state then setup diff --git a/Engine/source/scene/culling/sceneCullingState.cpp b/Engine/source/scene/culling/sceneCullingState.cpp index b8608160d..f3b4022fa 100644 --- a/Engine/source/scene/culling/sceneCullingState.cpp +++ b/Engine/source/scene/culling/sceneCullingState.cpp @@ -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(); diff --git a/Engine/source/scene/culling/sceneCullingState.h b/Engine/source/scene/culling/sceneCullingState.h index b7a231da8..b63b219c2 100644 --- a/Engine/source/scene/culling/sceneCullingState.h +++ b/Engine/source/scene/culling/sceneCullingState.h @@ -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; } diff --git a/Engine/source/scene/reflector.cpp b/Engine/source/scene/reflector.cpp index 91a29f99b..2b96737e6 100644 --- a/Engine/source/scene/reflector.cpp +++ b/Engine/source/scene/reflector.cpp @@ -420,7 +420,7 @@ void CubeReflector::updateFace( const ReflectParams ¶ms, U32 faceidx ) reflectRenderState.disableAdvancedLightingBins(true); // render scene - LIGHTMGR->registerGlobalLights( &reflectRenderState.getFrustum(), false ); + LIGHTMGR->registerGlobalLights( &reflectRenderState.getCullingFrustum(), false ); gClientSceneGraph->renderSceneNoLights( &reflectRenderState, mDesc->objectTypeMask ); LIGHTMGR->unregisterAllLights(); diff --git a/Engine/source/scene/sceneManager.cpp b/Engine/source/scene/sceneManager.cpp index 6db76d590..3fcd37422 100644 --- a/Engine/source/scene/sceneManager.cpp +++ b/Engine/source/scene/sceneManager.cpp @@ -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 ); diff --git a/Engine/source/scene/sceneRenderState.h b/Engine/source/scene/sceneRenderState.h index 7a66e40aa..4b8fd200d 100644 --- a/Engine/source/scene/sceneRenderState.h +++ b/Engine/source/scene/sceneRenderState.h @@ -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; }