bool SceneManager::addObjectToScene( SceneObject* object ) { AssertFatal( !object->mSceneManager, "SceneManager::addObjectToScene - Object already part of a scene" ); // Mark the object as belonging to us. object->mSceneManager = this; // Register with managers except its the root zone. if( !dynamic_cast< SceneRootZone* >( object ) ) { // Add to container. getContainer()->addObject( object ); // Register the object with the zone manager. if( getZoneManager() ) getZoneManager()->registerObject( object ); } // Notify the object. return object->onSceneAdd(); }
void SceneManager::notifyObjectDirty( SceneObject* object ) { // Update container state. if( object->mContainer ) object->mContainer->checkBins( object ); // Mark zoning state as dirty. if( getZoneManager() ) getZoneManager()->notifyObjectChanged( object ); }
void SceneManager::removeObjectFromScene( SceneObject* obj ) { AssertFatal( obj->getSceneManager() == this, "SceneManager::removeObjectFromScene - Object not part of SceneManager" ); // Notify the object. obj->onSceneRemove(); // Remove the object from the container. getContainer()->removeObject( obj ); // Remove the object from the zoning system. if( getZoneManager() ) getZoneManager()->unregisterObject( obj ); // Clear out the reference to us. obj->mSceneManager = NULL; }
void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone ) { AssertFatal( this == gClientSceneGraph, "SceneManager::_buildSceneGraph - Only the client scenegraph can support this call!" ); PROFILE_SCOPE( SceneGraph_batchRenderImages ); // In the editor, override the type mask for diffuse passes. if( gEditingMission && state->isDiffusePass() ) objectMask = EDITOR_RENDER_TYPEMASK; // Update the zoning state and traverse zones. if( getZoneManager() ) { // Update. getZoneManager()->updateZoningState(); // If zone culling isn't disabled, traverse the // zones now. if( !state->getCullingState().disableZoneCulling() ) { // Find the start zone if we haven't already. if( !baseObject ) { getZoneManager()->findZone( state->getCameraPosition(), baseObject, baseZone ); AssertFatal( baseObject != NULL, "SceneManager::_renderScene - findZone() did not return an object" ); } // Traverse zones starting in base object. SceneTraversalState traversalState( &state->getCullingState() ); PROFILE_START( Scene_traverseZones ); baseObject->traverseZones( &traversalState, baseZone ); PROFILE_END(); // Set the scene render box to the area we have traversed. state->setRenderArea( traversalState.getTraversedArea() ); } } // Set the query box for the container query. Never // make it larger than the frustum's AABB. In the editor, // always query the full frustum as that gives objects // the opportunity to render editor visualizations even if // they are otherwise not in view. if( !state->getFrustum().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 // its "walls". In that case the traversal area will be behind the frustum // (remember that the camera isn't where visibility starts, it's the near // distance). return; } Box3F queryBox = state->getFrustum().getBounds(); if( !gEditingMission ) { queryBox.minExtents.setMax( state->getRenderArea().minExtents ); queryBox.maxExtents.setMin( state->getRenderArea().maxExtents ); } PROFILE_START( Scene_cullObjects ); //TODO: We should split the codepaths here based on whether the outdoor zone has visible space. // If it has, we should use the container query-based path. // If it hasn't, we should fill the object list directly from the zone lists which will usually // include way fewer objects. // Gather all objects that intersect the scene render box. mBatchQueryList.clear(); getContainer()->findObjectList( queryBox, objectMask, &mBatchQueryList ); // Cull the list. U32 numRenderObjects = state->getCullingState().cullObjects( mBatchQueryList.address(), mBatchQueryList.size(), !state->isDiffusePass() ? SceneCullingState::CullEditorOverrides : 0 // Keep forced editor stuff out of non-diffuse passes. ); //HACK: If the control object is a Player and it is not in the render list, force // it into it. This really should be solved by collision bounds being separate from // object bounds; only because the Player class is using bounds not encompassing // the actual player object is it that we have this problem in the first place. // Note that we are forcing the player object into ALL passes here but such // is the power of proliferation of things done wrong. GameConnection* connection = GameConnection::getConnectionToServer(); if( connection ) { Player* player = dynamic_cast< Player* >( connection->getControlObject() ); if( player ) { mBatchQueryList.setSize( numRenderObjects ); if( !mBatchQueryList.contains( player ) ) { mBatchQueryList.push_back( player ); numRenderObjects ++; } } } PROFILE_END(); // Render the remaining objects. PROFILE_START( Scene_renderObjects ); state->renderObjects( mBatchQueryList.address(), numRenderObjects ); PROFILE_END(); // Render bounding boxes, if enabled. if( smRenderBoundingBoxes && state->isDiffusePass() ) { GFXDEBUGEVENT_SCOPE( Scene_renderBoundingBoxes, ColorI::WHITE ); GameBase* cameraObject = 0; if( connection ) cameraObject = connection->getCameraObject(); GFXStateBlockDesc desc; desc.setFillModeWireframe(); desc.setZReadWrite( true, false ); for( U32 i = 0; i < numRenderObjects; ++ i ) { SceneObject* object = mBatchQueryList[ i ]; // Skip global bounds object. if( object->isGlobalBounds() ) continue; // Skip camera object as we're viewing the scene from it. if( object == cameraObject ) continue; const Box3F& worldBox = object->getWorldBox(); GFX->getDrawUtil()->drawObjectBox( desc, Point3F( worldBox.len_x(), worldBox.len_y(), worldBox.len_z() ), worldBox.getCenter(), MatrixF::Identity, ColorI::WHITE ); } } }
void SceneManager::renderScene( SceneRenderState* renderState, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone ) { PROFILE_SCOPE( SceneGraph_renderScene ); // Get the lights for rendering the scene. PROFILE_START( SceneGraph_registerLights ); LIGHTMGR->registerGlobalLights( &renderState->getFrustum(), false ); PROFILE_END(); // If its a diffuse pass, update the current ambient light level. // To do that find the starting zone and determine whether it has a custom // ambient light color. If so, pass it on to the ambient light manager. // If not, use the ambient light color of the sunlight. // // Note that we retain the starting zone information here and pass it // on to renderSceneNoLights so that we don't need to look it up twice. if( renderState->isDiffusePass() ) { if( !baseObject && getZoneManager() ) { getZoneManager()->findZone( renderState->getCameraPosition(), baseObject, baseZone ); AssertFatal( baseObject != NULL, "SceneManager::renderScene - findZone() did not return an object" ); } ColorF zoneAmbient; if( baseObject && baseObject->getZoneAmbientLightColor( baseZone, zoneAmbient ) ) mAmbientLightColor.setTargetValue( zoneAmbient ); else { const LightInfo* sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType ); if( sunlight ) mAmbientLightColor.setTargetValue( sunlight->getAmbient() ); } renderState->setAmbientLightColor( mAmbientLightColor.getCurrentValue() ); } // Trigger the pre-render signal. PROFILE_START( SceneGraph_preRenderSignal); mCurrentRenderState = renderState; getPreRenderSignal().trigger( this, renderState ); mCurrentRenderState = NULL; PROFILE_END(); // Render the scene. renderSceneNoLights( renderState, objectMask, baseObject, baseZone ); // Trigger the post-render signal. PROFILE_START( SceneGraphRender_postRenderSignal ); mCurrentRenderState = renderState; getPostRenderSignal().trigger( this, renderState ); mCurrentRenderState = NULL; PROFILE_END(); // Remove the previously registered lights. PROFILE_START( SceneGraph_unregisterLights); LIGHTMGR->unregisterAllLights(); PROFILE_END(); }
void SceneManager::renderScene( SceneRenderState* renderState, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone ) { PROFILE_SCOPE( SceneGraph_renderScene ); // Get the lights for rendering the scene. PROFILE_START( SceneGraph_registerLights ); LIGHTMGR->registerGlobalLights( &renderState->getCullingFrustum(), false ); PROFILE_END(); // If its a diffuse pass, update the current ambient light level. // To do that find the starting zone and determine whether it has a custom // ambient light color. If so, pass it on to the ambient light manager. // If not, use the ambient light color of the sunlight. // // Note that we retain the starting zone information here and pass it // on to renderSceneNoLights so that we don't need to look it up twice. if( renderState->isDiffusePass() ) { if( !baseObject && getZoneManager() ) { getZoneManager()->findZone( renderState->getCameraPosition(), baseObject, baseZone ); AssertFatal( baseObject != NULL, "SceneManager::renderScene - findZone() did not return an object" ); } ColorF zoneAmbient; if( baseObject && baseObject->getZoneAmbientLightColor( baseZone, zoneAmbient ) ) mAmbientLightColor.setTargetValue( zoneAmbient ); else { const LightInfo* sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType ); if( sunlight ) mAmbientLightColor.setTargetValue( sunlight->getAmbient() ); } renderState->setAmbientLightColor( mAmbientLightColor.getCurrentValue() ); } // Trigger the pre-render signal. PROFILE_START( SceneGraph_preRenderSignal); mCurrentRenderState = renderState; getPreRenderSignal().trigger( this, renderState ); mCurrentRenderState = NULL; PROFILE_END(); // Render the scene. if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide) { // Store previous values RectI originalVP = GFX->getViewport(); MatrixF originalWorld = GFX->getWorldMatrix(); Frustum originalFrustum = GFX->getFrustum(); Point2F projOffset = GFX->getCurrentProjectionOffset(); const FovPort *currentFovPort = GFX->getStereoFovPort(); const MatrixF *eyeTransforms = GFX->getStereoEyeTransforms(); const MatrixF *worldEyeTransforms = GFX->getInverseStereoEyeTransforms(); // Render left half of display GFX->activateStereoTarget(0); GFX->beginField(); GFX->setWorldMatrix(worldEyeTransforms[0]); Frustum gfxFrustum = originalFrustum; MathUtils::makeFovPortFrustum(&gfxFrustum, gfxFrustum.isOrtho(), gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[0], eyeTransforms[0]); GFX->setFrustum(gfxFrustum); SceneCameraState cameraStateLeft = SceneCameraState::fromGFX(); SceneRenderState renderStateLeft( this, renderState->getScenePassType(), cameraStateLeft ); renderStateLeft.setSceneRenderStyle(SRS_SideBySide); renderStateLeft.setSceneRenderField(0); renderSceneNoLights( &renderStateLeft, objectMask, baseObject, baseZone ); // Indicate that we've just finished a field //GFX->clear(GFXClearTarget | GFXClearZBuffer | GFXClearStencil, ColorI(255,0,0), 1.0f, 0); GFX->endField(); // Render right half of display GFX->activateStereoTarget(1); GFX->beginField(); GFX->setWorldMatrix(worldEyeTransforms[1]); gfxFrustum = originalFrustum; MathUtils::makeFovPortFrustum(&gfxFrustum, gfxFrustum.isOrtho(), gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[1], eyeTransforms[1]); GFX->setFrustum(gfxFrustum); SceneCameraState cameraStateRight = SceneCameraState::fromGFX(); SceneRenderState renderStateRight( this, renderState->getScenePassType(), cameraStateRight ); renderStateRight.setSceneRenderStyle(SRS_SideBySide); renderStateRight.setSceneRenderField(1); renderSceneNoLights( &renderStateRight, objectMask, baseObject, baseZone ); // Indicate that we've just finished a field //GFX->clear(GFXClearTarget | GFXClearZBuffer | GFXClearStencil, ColorI(0,255,0), 1.0f, 0); GFX->endField(); // Restore previous values GFX->setWorldMatrix(originalWorld); GFX->setFrustum(originalFrustum); GFX->setViewport(originalVP); } else { renderSceneNoLights( renderState, objectMask, baseObject, baseZone ); } // Trigger the post-render signal. PROFILE_START( SceneGraphRender_postRenderSignal ); mCurrentRenderState = renderState; getPostRenderSignal().trigger( this, renderState ); mCurrentRenderState = NULL; PROFILE_END(); // Remove the previously registered lights. PROFILE_START( SceneGraph_unregisterLights); LIGHTMGR->unregisterAllLights(); PROFILE_END(); }
void SceneManager::renderScene( SceneRenderState* renderState, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone ) { PROFILE_SCOPE( SceneGraph_renderScene ); // Get the lights for rendering the scene. PROFILE_START( SceneGraph_registerLights ); LIGHTMGR->registerGlobalLights( &renderState->getFrustum(), false ); PROFILE_END(); // If its a diffuse pass, update the current ambient light level. // To do that find the starting zone and determine whether it has a custom // ambient light color. If so, pass it on to the ambient light manager. // If not, use the ambient light color of the sunlight. // // Note that we retain the starting zone information here and pass it // on to renderSceneNoLights so that we don't need to look it up twice. if( renderState->isDiffusePass() ) { if( !baseObject && getZoneManager() ) { getZoneManager()->findZone( renderState->getCameraPosition(), baseObject, baseZone ); AssertFatal( baseObject != NULL, "SceneManager::renderScene - findZone() did not return an object" ); } ColorF zoneAmbient; if( baseObject && baseObject->getZoneAmbientLightColor( baseZone, zoneAmbient ) ) mAmbientLightColor.setTargetValue( zoneAmbient ); else { const LightInfo* sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType ); if( sunlight ) mAmbientLightColor.setTargetValue( sunlight->getAmbient() ); } renderState->setAmbientLightColor( mAmbientLightColor.getCurrentValue() ); } // Trigger the pre-render signal. PROFILE_START( SceneGraph_preRenderSignal); mCurrentRenderState = renderState; getPreRenderSignal().trigger( this, renderState ); mCurrentRenderState = NULL; PROFILE_END(); // Render the scene. if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide) { // Store previous values RectI originalVP = GFX->getViewport(); MatrixF originalWorld = GFX->getWorldMatrix(); Point2F projOffset = GFX->getCurrentProjectionOffset(); Point3F eyeOffset = GFX->getStereoEyeOffset(); // Render left half of display RectI leftVP = originalVP; leftVP.extent.x *= 0.5; GFX->setViewport(leftVP); MatrixF leftWorldTrans(true); leftWorldTrans.setPosition(Point3F(eyeOffset.x, eyeOffset.y, eyeOffset.z)); MatrixF leftWorld(originalWorld); leftWorld.mulL(leftWorldTrans); GFX->setWorldMatrix(leftWorld); Frustum gfxFrustum = GFX->getFrustum(); gfxFrustum.setProjectionOffset(Point2F(projOffset.x, projOffset.y)); GFX->setFrustum(gfxFrustum); SceneCameraState cameraStateLeft = SceneCameraState::fromGFX(); SceneRenderState renderStateLeft( this, renderState->getScenePassType(), cameraStateLeft ); renderStateLeft.setSceneRenderStyle(SRS_SideBySide); renderStateLeft.setSceneRenderField(0); renderSceneNoLights( &renderStateLeft, objectMask, baseObject, baseZone ); // Render right half of display RectI rightVP = originalVP; rightVP.extent.x *= 0.5; rightVP.point.x += rightVP.extent.x; GFX->setViewport(rightVP); MatrixF rightWorldTrans(true); rightWorldTrans.setPosition(Point3F(-eyeOffset.x, eyeOffset.y, eyeOffset.z)); MatrixF rightWorld(originalWorld); rightWorld.mulL(rightWorldTrans); GFX->setWorldMatrix(rightWorld); gfxFrustum = GFX->getFrustum(); gfxFrustum.setProjectionOffset(Point2F(-projOffset.x, projOffset.y)); GFX->setFrustum(gfxFrustum); SceneCameraState cameraStateRight = SceneCameraState::fromGFX(); SceneRenderState renderStateRight( this, renderState->getScenePassType(), cameraStateRight ); renderStateRight.setSceneRenderStyle(SRS_SideBySide); renderStateRight.setSceneRenderField(1); renderSceneNoLights( &renderStateRight, objectMask, baseObject, baseZone ); // Restore previous values GFX->setWorldMatrix(originalWorld); gfxFrustum.clearProjectionOffset(); GFX->setFrustum(gfxFrustum); GFX->setViewport(originalVP); } else { renderSceneNoLights( renderState, objectMask, baseObject, baseZone ); } // Trigger the post-render signal. PROFILE_START( SceneGraphRender_postRenderSignal ); mCurrentRenderState = renderState; getPostRenderSignal().trigger( this, renderState ); mCurrentRenderState = NULL; PROFILE_END(); // Remove the previously registered lights. PROFILE_START( SceneGraph_unregisterLights); LIGHTMGR->unregisterAllLights(); PROFILE_END(); }