Merge pull request #528 from DavidWyand-GG/OculusRiftUpdate2

SceneCullingState with culling and camera frustum
This commit is contained in:
David Wyand 2013-11-07 13:27:50 -08:00
commit 8c98aad0b3
22 changed files with 161 additions and 47 deletions

View file

@ -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 );

View file

@ -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?

View file

@ -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

View file

@ -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;

View file

@ -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 )

View file

@ -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() );

View file

@ -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();

View file

@ -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 );

View file

@ -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 ||

View file

@ -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 ) )

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 )

View file

@ -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;

View file

@ -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

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