#include "OgreOcclusionCullingSceneManager.h" #include "OgreVisibilityOptionsManager.h" #include #include #include #include #include #include #include #include #include #include #include #include "VspBspTree.h" #include "Containers.h" #include "ViewCellsManager.h" #include #include "OgreTypeConverter.h" #include "OgreMeshInstance.h" #include "common.h" #include "OgreBoundingBoxConverter.h" #include #include "IntersectableWrapper.h" #include "IVReader.h" #include "ObjReader.h" namespace Ogre { //----------------------------------------------------------------------- OcclusionCullingSceneManager::OcclusionCullingSceneManager( const String& name, GtpVisibility::VisibilityManager *visManager): TerrainSceneManager(name), mVisibilityManager(visManager), mShowVisualization(false), mRenderNodesForViz(false), mRenderNodesContentForViz(false), mVisualizeCulledNodes(false), mLeavePassesInQueue(0), mDelayRenderTransparents(true), mUseDepthPass(false), mIsDepthPassPhase(false), mUseItemBuffer(false), mIsItemBufferPhase(false), mCurrentEntityId(1), mEnableDepthWrite(true), mSkipTransparents(false), mRenderTransparentsForItemBuffer(true), mExecuteVertexProgramForAllPasses(false), mIsHierarchicalCulling(false), mViewCellsLoaded(false), mUseViewCells(false), mUseVisibilityFilter(false), mCurrentViewCell(NULL), mElementaryViewCell(NULL), mDeleteQueueAfterRendering(true), mNormalExecution(false), mShowViewCells(false), mViewCellsGeometryLoaded(false), mShowTerrain(false), mViewCellsFilename(""), mFilename("terrain"), mFlushRate(10), mCurrentFrame(0) { Ogre::LogManager::getSingleton(). logMessage("creating occlusion culling scene manager"); mHierarchyInterface = new OctreeHierarchyInterface(this, mDestRenderSystem); if (0) { mDisplayNodes = true; mShowBoundingBoxes = true; mShowBoxes = true; } // TODO: set maxdepth to reasonable value mMaxDepth = 50; mObjReader = new ObjReader(this); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::InitDepthPass() { MaterialPtr depthMat = MaterialManager::getSingleton().getByName("Visibility/DepthPass"); if (depthMat.isNull()) { depthMat = MaterialManager::getSingleton().create( "Visibility/DepthPass", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mDepthPass = depthMat->getTechnique(0)->getPass(0); mDepthPass->setColourWriteEnabled(false); mDepthPass->setDepthWriteEnabled(true); mDepthPass->setLightingEnabled(false); } else { mDepthPass = depthMat->getTechnique(0)->getPass(0); } } //----------------------------------------------------------------------- OcclusionCullingSceneManager::~OcclusionCullingSceneManager() { OGRE_DELETE(mHierarchyInterface); CLEAR_CONTAINER(mObjects); OGRE_DELETE(mCurrentViewCell); OGRE_DELETE(mObjReader); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::InitItemBufferPass() { MaterialPtr itemBufferMat = MaterialManager::getSingleton(). getByName("Visibility/ItemBufferPass"); if (itemBufferMat.isNull()) { // Init itemBufferMat = MaterialManager::getSingleton().create("Visibility/ItemBufferPass", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mItemBufferPass = itemBufferMat->getTechnique(0)->getPass(0); mItemBufferPass->setColourWriteEnabled(true); mItemBufferPass->setDepthWriteEnabled(true); mItemBufferPass->setLightingEnabled(true); //mItemBufferPass->setLightingEnabled(false); } else { mItemBufferPass = itemBufferMat->getTechnique(0)->getPass(0); } //mItemBufferPass->setAmbient(1, 1, 0); } //------------------------------------------------------------------------- #if 1 void OcclusionCullingSceneManager::setWorldGeometry(DataStreamPtr& stream, const String& typeName) { // Clear out any existing world resources (if not default) if (ResourceGroupManager::getSingleton().getWorldResourceGroupName() != ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) { ResourceGroupManager::getSingleton().clearResourceGroup( ResourceGroupManager::getSingleton().getWorldResourceGroupName()); } destroyLevelIndexes(); mTerrainPages.clear(); // Load the configuration loadConfig(stream); ////////////// // file loading // load the scene LoadScene(mFilename, mViewCellsFilename); // load view cells: load later ... if (0) mViewCellsLoaded = LoadViewCells(mViewCellsFilename); if (mShowTerrain) { initLevelIndexes(); // Resize the octree, allow for 1 page for now float max_x = mOptions.scale.x * mOptions.pageSize; float max_y = mOptions.scale.y;// * mOptions.pageSize; float max_z = mOptions.scale.z * mOptions.pageSize; float maxAxis = std::max(max_x, max_y); maxAxis = std::max(maxAxis, max_z); resize(AxisAlignedBox( 0, 0, 0, maxAxis, maxAxis, maxAxis)); //resize(AxisAlignedBox( 0, 0, 0, max_x, max_y, max_z )); setupTerrainMaterial(); setupTerrainPages(); } } #endif //------------------------------------------------------------------------- void OcclusionCullingSceneManager::loadConfig(DataStreamPtr& stream) { // Set up the options ConfigFile config; String val; LogManager::getSingleton().logMessage("****** OcclusionCullingSceneManager Options ********"); config.load(stream); std::stringstream d; val = config.getSetting("DepthPass"); if (!val.empty()) { mUseDepthPass = atoi(val.c_str()); } if (mUseDepthPass) LogManager::getSingleton().logMessage("using depth"); else LogManager::getSingleton().logMessage("not using depth"); val = config.getSetting("FlushQueue"); if (!val.empty()) { mDeleteQueueAfterRendering = atoi(val.c_str()); } if (mDeleteQueueAfterRendering) LogManager::getSingleton().logMessage("flushing queue"); else LogManager::getSingleton().logMessage("not flushing queue"); val = config.getSetting("Scene"); if (!val.empty()) { mFilename = val.c_str(); // load terrain instead of scene if (mFilename == "terrain") { mShowTerrain = true; LogManager::getSingleton().logMessage("loading terrain"); } else { mShowTerrain = false; LogManager::getSingleton().logMessage("loading geometry"); } } if (!mShowTerrain) { val = config.getSetting("ViewCells"); if (!val.empty()) { mViewCellsFilename = val; } } val = config.getSetting("OnlineCullingAlgorithm"); if (!val.empty()) { GtpVisibility::VisibilityEnvironment::CullingManagerType algorithm; if (val == "CHC") { algorithm = GtpVisibility::VisibilityEnvironment::COHERENT_HIERARCHICAL_CULLING; } else if (val == "SWC") { algorithm = GtpVisibility::VisibilityEnvironment::STOP_AND_WAIT_CULLING; } else if (val == "VFC") { algorithm = GtpVisibility::VisibilityEnvironment::FRUSTUM_CULLING; } else // default rendering { algorithm = GtpVisibility::VisibilityEnvironment::NUM_CULLING_MANAGERS; mNormalExecution = true; } mVisibilityManager->SetCullingManager(algorithm); d << "setting algorithm to: " << algorithm; LogManager::getSingleton().logMessage(d.str()); } ///////////// // terrain options if (!mShowTerrain) return; val = config.getSetting("DetailTile"); if (!val.empty()) setDetailTextureRepeat(atoi(val.c_str())); val = config.getSetting("MaxMipMapLevel"); if (!val.empty()) setMaxGeoMipMapLevel(atoi(val.c_str())); val = config.getSetting("PageSize"); if (!val.empty()) setPageSize(atoi(val.c_str())); else OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing option 'PageSize'", "TerrainSceneManager::loadConfig"); val = config.getSetting("TileSize"); if (!val.empty()) setTileSize(atoi(val.c_str())); else OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing option 'TileSize'", "TerrainSceneManager::loadConfig"); Vector3 v = Vector3::UNIT_SCALE; val = config.getSetting( "PageWorldX" ); if ( !val.empty() ) v.x = atof( val.c_str() ); val = config.getSetting( "MaxHeight" ); if ( !val.empty() ) v.y = atof( val.c_str() ); val = config.getSetting( "PageWorldZ" ); if ( !val.empty() ) v.z = atof( val.c_str() ); // Scale x/z relative to pagesize v.x /= mOptions.pageSize; v.z /= mOptions.pageSize; setScale(v); val = config.getSetting( "MaxPixelError" ); if ( !val.empty() ) setMaxPixelError(atoi( val.c_str() )); mDetailTextureName = config.getSetting( "DetailTexture" ); mWorldTextureName = config.getSetting( "WorldTexture" ); if ( config.getSetting( "VertexColours" ) == "yes" ) mOptions.coloured = true; if ( config.getSetting( "VertexNormals" ) == "yes" ) mOptions.lit = true; if ( config.getSetting( "UseTriStrips" ) == "yes" ) setUseTriStrips(true); if ( config.getSetting( "VertexProgramMorph" ) == "yes" ) setUseLODMorph(true); val = config.getSetting( "LODMorphStart"); if ( !val.empty() ) setLODMorphStart(atof(val.c_str())); val = config.getSetting( "CustomMaterialName" ); if ( !val.empty() ) setCustomMaterial(val); val = config.getSetting( "MorphLODFactorParamName" ); if ( !val.empty() ) setCustomMaterialMorphFactorParam(val); val = config.getSetting( "MorphLODFactorParamIndex" ); if ( !val.empty() ) setCustomMaterialMorphFactorParam(atoi(val.c_str())); // Now scan through the remaining settings, looking for any PageSource // prefixed items String pageSourceName = config.getSetting("PageSource"); if (pageSourceName == "") { OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing option 'PageSource'", "TerrainSceneManager::loadConfig"); } TerrainPageSourceOptionList optlist; ConfigFile::SettingsIterator setIt = config.getSettingsIterator(); while (setIt.hasMoreElements()) { String name = setIt.peekNextKey(); String value = setIt.getNext(); if (StringUtil::startsWith(name, pageSourceName, false)) { optlist.push_back(TerrainPageSourceOption(name, value)); } } // set the page source selectPageSource(pageSourceName, optlist); LogManager::getSingleton().logMessage("****** Finished OcclusionCullingSceneManager Options ********"); } void OcclusionCullingSceneManager::MailPvsObjects() { GtpVisibilityPreprocessor::ObjectPvsIterator pit = mCurrentViewCell->GetPvs().GetIterator(); while (pit.HasMoreEntries()) { GtpVisibilityPreprocessor::Intersectable *obj = pit.Next(); if (obj->Type() != GtpVisibilityPreprocessor::Intersectable::ENGINE_INTERSECTABLE) continue; EngineIntersectable *oi = static_cast(obj); EntityContainer *entries = oi->GetItem(); EntityContainer::const_iterator eit, eit_end = entries->end(); for (eit = entries->begin(); eit != eit_end; ++ eit) { (*eit)->setUserAny(Any((int)0)); } } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::ShowViewCellsGeometry() {/* // show only current view cell if (!mShowViewCells) { const int id = mCurrentViewCell->GetId(); MovableMap::iterator fit = mViewCellsGeometry.find(id); if ((fit != mViewCellsGeometry.end()) && (*fit).second) (*fit).second->_updateRenderQueue(getRenderQueue()); } else { MovableMap::const_iterator mit, mit_end = mViewCellsGeometry.end(); for (mit = mViewCellsGeometry.begin(); mit != mit_end; ++ mit) { if ((*mit).second) (*mit).second->_updateRenderQueue(getRenderQueue()); } }*/ } void OcclusionCullingSceneManager::RenderPvsEntry(GtpVisibilityPreprocessor::Intersectable *obj) { switch (obj->Type()) { case GtpVisibilityPreprocessor::Intersectable::OGRE_MESH_INSTANCE: { OgreMeshInstance *omi = static_cast(obj); omi->GetEntity()->_updateRenderQueue(getRenderQueue()); } break; case GtpVisibilityPreprocessor::Intersectable::ENGINE_INTERSECTABLE: { EngineIntersectable *oi = static_cast(obj); EntityContainer *entries = oi->GetItem(); EntityContainer::const_iterator eit, eit_end = entries->end(); for (eit = entries->begin(); eit != eit_end; ++ eit) { Entity *ent = *eit; // mailing hack Any newAny = ent->getUserAny(); int flt = any_cast(newAny); if (any_cast(newAny) == 0) { ent->setUserAny(Any((int)1)); ent->_updateRenderQueue(getRenderQueue()); } } } break; default: break; } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::SetObjectVisible(GtpVisibilityPreprocessor::Intersectable *entry, const bool visible) { switch (entry->Type()) { case GtpVisibilityPreprocessor::Intersectable::OGRE_MESH_INSTANCE: { OgreMeshInstance *omi = static_cast(entry); omi->GetEntity()->setVisible(visible); //GtpVisibilityPreprocessor::Debug << "assigned id " << omi->GetId() << endl; } break; case GtpVisibilityPreprocessor::Intersectable::ENGINE_INTERSECTABLE: { EngineIntersectable *oi = static_cast(entry); EntityContainer *entries = oi->GetItem(); EntityContainer::const_iterator eit, eit_end = entries->end(); for (eit = entries->begin(); eit != eit_end; ++ eit) { Entity *ent = *eit; ent->setVisible(visible); } } break; default: break; } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::PrepareVisualization(Camera *cam) { // add player camera for visualization purpose try { Camera *c; if ((c = getCamera("PlayerCam")) != NULL) { getRenderQueue()->addRenderable(c); } } catch (...) { // ignore } // add bounding boxes of rendered objects if (0) for (BoxList::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { getRenderQueue()->addRenderable(*it); } // show current view cell geometry if (mCurrentViewCell)// && mCurrentViewCell->GetMesh()) { //const bool showSingleViewCell = true; if (mViewCellsGeometryLoaded) { ShowViewCellsGeometry(); } ////////// //-- set PVS of view cell visible GtpVisibilityPreprocessor::ObjectPvsIterator pit = mCurrentViewCell->GetPvs().GetIterator(); MailPvsObjects(); while (pit.HasMoreEntries()) { RenderPvsEntry(pit.Next()); } } #if 0 if (mRenderNodesForViz || mRenderNodesContentForViz) { // HACK: change node material so it is better suited for visualization MaterialPtr nodeMat = MaterialManager::getSingleton().getByName("Core/NodeMaterial"); nodeMat->setAmbient(1, 1, 0); nodeMat->setLightingEnabled(true); nodeMat->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); for (NodeList::iterator it = mVisible.begin(); it != mVisible.end(); ++it) { if (mRenderNodesForViz) { // render the visible leaf nodes if ((*it)->numAttachedObjects() && !(*it)->numChildren() && ((*it)->getAttachedObject(0)->getMovableType() == "Entity") && (*it)->getAttachedObject(0)->isVisible()) { //getRenderQueue()->addRenderable((*it)); (*it)->_addToRenderQueue(cam, getRenderQueue(), false); } // add bounding boxes instead of node itself if (0) (*it)->_addBoundingBoxToQueue(getRenderQueue()); } // add renderables itself if (mRenderNodesContentForViz) { (*it)->_addToRenderQueue(cam, getRenderQueue(), false); } } } #endif } //----------------------------------------------------------------------- const Pass *OcclusionCullingSceneManager::_setPass(const Pass* pass, bool evenIfSuppressed) { if (mNormalExecution) { return SceneManager::_setPass(pass); } // TODO: setting vertex program is not efficient //Pass *usedPass = ((mIsDepthPassPhase && !pass->hasVertexProgram()) ? mDepthPass : pass); // set depth fill pass if we currently do not make an aabb occlusion query const bool useDepthPass = mUseDepthPass && mIsDepthPassPhase && !mHierarchyInterface->IsBoundingBoxQuery(); const IlluminationRenderStage savedStage = mIlluminationStage; if (useDepthPass) { // set illumination stage to NONE so no shadow material is used // for depth pass or for occlusion query if (mIsDepthPassPhase || mHierarchyInterface->IsBoundingBoxQuery()) { mIlluminationStage = IRS_NONE; } //--- set vertex program of current pass in order to set correct depth if (mExecuteVertexProgramForAllPasses && mIsDepthPassPhase && pass->hasVertexProgram()) { // add vertex program of current pass to depth pass mDepthPass->setVertexProgram(pass->getVertexProgramName()); if (mDepthPass->hasVertexProgram()) { const GpuProgramPtr& prg = mDepthPass->getVertexProgram(); // Load this program if not done already if (!prg->isLoaded()) prg->load(); // Copy params mDepthPass->setVertexProgramParameters(pass->getVertexProgramParameters()); } } else if (mDepthPass->hasVertexProgram()) { // reset vertex program mDepthPass->setVertexProgram(""); } } const Pass *usedPass = useDepthPass ? mDepthPass : pass; // save old depth write: needed for item buffer const bool IsDepthWrite = usedPass->getDepthWriteEnabled(); // global option which enables / disables depth writes if (!mEnableDepthWrite) { //usedPass->setDepthWriteEnabled(false); } //else if (mIsItemBufferPass) {usedPass = mItemBufferPass;} //-- set actual pass here const Pass *result = SceneManager::_setPass(usedPass); // reset depth write if (!mEnableDepthWrite) { //usedPass->setDepthWriteEnabled(IsDepthWrite); } // reset illumination stage mIlluminationStage = savedStage; return result; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::myFindVisibleObjects(Camera* cam, bool onlyShadowCasters) { if (mShowVisualization) { ////////////// //-- show visible scene nodes and octree bounding boxes from last frame PrepareVisualization(cam); // lists only used for visualization mVisible.clear(); mBoxes.clear(); return; } // lists only used for visualization mVisible.clear(); mBoxes.clear(); /////////// //-- set visibility according to pvs of current view cell UpdatePvs(cam); // standard rendering in first pass if (!mNormalExecution && mUseDepthPass) { RenderDepthPass(); } else { // hierarchical culling interleaves identification // and rendering of objects in _renderVisibibleObjects // for the shadow pass we use only standard rendering // because shadows have low occlusion anyway if ((mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE && mIlluminationStage == IRS_RENDER_TO_TEXTURE) || mNormalExecution) { OctreeSceneManager::_findVisibleObjects(cam, onlyShadowCasters); } // only shadow casters will be rendered in shadow texture pass //if (0) mHierarchyInterface->SetOnlyShadowCasters(onlyShadowCasters); } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_renderVisibleObjects() { const bool flushQueue = mDeleteQueueAfterRendering && ((mCurrentFrame % mFlushRate) == 0); ++ mCurrentFrame; if (mNormalExecution) { // the standard octree rendering mode TerrainSceneManager::_renderVisibleObjects(); getRenderQueue()->clear(flushQueue); return; } InitItemBufferPass(); // create material for item buffer pass // save ambient light to reset later ColourValue savedAmbient = mAmbientLight; //////////////////// //-- apply standard rendering for some modes //-- (e.g., the visualization mode, the shadow pass) if (mUseDepthPass || mShowVisualization || (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE && mIlluminationStage == IRS_RENDER_TO_TEXTURE)) { IlluminationRenderStage savedStage = mIlluminationStage; if (mShowVisualization) { // disable illumination stage to prevent rendering shadows mIlluminationStage = IRS_NONE; } // standard rendering for shadow maps because of performance TerrainSceneManager::_renderVisibleObjects(); mIlluminationStage = savedStage; } else //-- the hierarchical culling algorithm { // note matt: this is also called in TerrainSceneManager: really necessary? mDestRenderSystem -> setLightingEnabled(false); if (mUseItemBuffer) { // don't render backgrounds for item buffer clearSpecialCaseRenderQueues(); getRenderQueue()->clear(); } //////////////////// //-- hierarchical culling // the objects of different layers (e.g., background, scene, // overlay) must be identified and rendered one after another // first render all early skies clearSpecialCaseRenderQueues(); addSpecialCaseRenderQueue(RENDER_QUEUE_BACKGROUND); addSpecialCaseRenderQueue(RENDER_QUEUE_SKIES_EARLY); setSpecialCaseRenderQueueMode(SceneManager::SCRQM_INCLUDE); TerrainSceneManager::_renderVisibleObjects(); #ifdef GTP_VISIBILITY_MODIFIED_OGRE // delete previously rendered content _deleteRenderedQueueGroups(); #endif /////////////////// //-- prepare queue for visible objects (i.e., all but overlay and skies late) clearSpecialCaseRenderQueues(); addSpecialCaseRenderQueue(RENDER_QUEUE_SKIES_LATE); addSpecialCaseRenderQueue(RENDER_QUEUE_OVERLAY); // exclude these queues from hierarchical rendering setSpecialCaseRenderQueueMode(SceneManager::SCRQM_EXCLUDE); // set all necessary parameters for // hierarchical visibility culling and rendering InitVisibilityCulling(mCameraInProgress); /** * the hierarchical culling algorithm * for depth pass: we just find objects and update depth buffer * for "delayed" rendering: we render some passes afterwards * e.g., transparents, because they need front-to-back sorting **/ mVisibilityManager->ApplyVisibilityCulling(); // delete remaining renderables from queue: // all which are not in mLeavePassesInQueue) #ifdef GTP_VISIBILITY_MODIFIED_OGRE _deleteRenderedQueueGroups(mLeavePassesInQueue); #endif ///////////// //-- reset parameters needed during hierarchical rendering mIsItemBufferPhase = false; mSkipTransparents = false; mIsHierarchicalCulling = false; mLeavePassesInQueue = 0; ///////////// //-- now we can render all remaining queue objects //-- used for depth pass, transparents, overlay clearSpecialCaseRenderQueues(); TerrainSceneManager::_renderVisibleObjects(); } // end hierarchical culling // HACK: set the new render level index, important to avoid cracks // in terrain caused by LOD TerrainRenderable::NextRenderLevelIndex(); // reset ambient light setAmbientLight(savedAmbient); // almost same effect as below getRenderQueue()->clear(flushQueue); if (0) WriteLog(); // write out stats } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_updateSceneGraph(Camera* cam) { if (mNormalExecution) { TerrainSceneManager::_updateSceneGraph(cam); return; } mVisibilityManager->GetCullingManager()->SetHierarchyInterface(mHierarchyInterface); mHierarchyInterface->SetRenderSystem(mDestRenderSystem); TerrainSceneManager::_updateSceneGraph(cam); } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::setOption(const String & key, const void * val) { if (key == "UseDepthPass") { mUseDepthPass = (*static_cast(val)); return true; } if (key == "PrepareVisualization") { mShowVisualization = (*static_cast(val)); return true; } if (key == "RenderNodesForViz") { mRenderNodesForViz = (*static_cast(val)); return true; } if (key == "RenderNodesContentForViz") { mRenderNodesContentForViz = (*static_cast(val)); return true; } if (key == "SkyBoxEnabled") { mSkyBoxEnabled = (*static_cast(val)); return true; } if (key == "SkyPlaneEnabled") { mSkyPlaneEnabled = (*static_cast(val)); return true; } if (key == "SkyDomeEnabled") { mSkyDomeEnabled = (*static_cast(val)); return true; } if (key == "VisualizeCulledNodes") { mVisualizeCulledNodes = (*static_cast(val)); return true; } if (key == "DelayRenderTransparents") { //LoadScene(mFilename, mViewCellsFilename); mDelayRenderTransparents = (*static_cast(val)); return true; } if (key == "DepthWrite") { mEnableDepthWrite = (*static_cast(val)); return true; } if (key == "UseItemBuffer") { mUseItemBuffer = (*static_cast(val)); return true; } if (key == "ExecuteVertexProgramForAllPasses") { mExecuteVertexProgramForAllPasses = (*static_cast(val)); return true; } if (key == "RenderTransparentsForItemBuffer") { mRenderTransparentsForItemBuffer = (*static_cast(val)); return true; } else if (key == "FlushQueue") { mDeleteQueueAfterRendering = (*static_cast(val)); return true; } if (key == "NodeVizScale") { OctreeNode::setVizScale(*static_cast(val)); return true; } if (key == "UseViewCells") { if (!mViewCellsLoaded) { // try to load view cells mViewCellsLoaded = LoadViewCells(mViewCellsFilename); } if (!mViewCellsLoaded) return false; // only use this option if view cells are available mUseViewCells = *static_cast(val); // reset view cell OGRE_DELETE(mCurrentViewCell); if (mUseViewCells) { mCurrentViewCell = mViewCellsManager->GenerateViewCell(); } // view cell corresponding to leaf in the view cell hierarchy mElementaryViewCell = NULL; // all objects are set to invisible per default SetObjectsVisible(!mUseViewCells); MovableObjectIterator movit = getMovableObjectIterator("Entity"); while (movit.hasMoreElements()) { Entity *ent = static_cast(movit.getNext()); ent->setVisible(!mUseViewCells); } return true; } if (key == "ShowViewCells") { // only use this option if view cells are available if (mViewCellsLoaded) { mShowViewCells = *static_cast(val); // if we decide use view cells // all objects are set to invisible per default VisualizeViewCells(mShowViewCells); } return true; } if (key == "NormalExecution") { mNormalExecution = *static_cast(val); return true; } if (key == "ShowTerrain") { mShowTerrain = *static_cast(val); return true; } if (key == "UseVisibilityFilter") { mUseVisibilityFilter = *static_cast(val); // set null => recomputation of the pvs mElementaryViewCell = NULL; return true; } if (key == "ViewCellsLoaded") { return mViewCellsLoaded; } return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface). setOption(key, val) || TerrainSceneManager::setOption(key, val); } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::getOption(const String &key, void *val) { if (key == "NumHierarchyNodes") { * static_cast(val) = (unsigned int)mNumOctants; return true; } if (key == "VisibilityManager") { * static_cast(val) = (GtpVisibility::VisibilityManager *)mVisibilityManager; return true; } if (key == "HierarchInterface") { * static_cast(val) = (GtpVisibility::HierarchyInterface *)mHierarchyInterface; return true; } if (key == "ShowTerrain") { * static_cast(val) = (bool *)mShowTerrain; return true; } if (key == "UseDepthPass") { * static_cast(val) = (bool *)mUseDepthPass; return true; } if (key == "FlushQueue") { * static_cast(val) = (bool *)mDeleteQueueAfterRendering; return true; } if (key == "NormalExecution") { * static_cast(val) = (bool *)mNormalExecution; return true; } if (key == "Algorithm") { GtpVisibility::VisibilityEnvironment::CullingManagerType algorithm = mVisibilityManager->GetCullingManagerType(); * static_cast(val) = (unsigned int)algorithm; getRenderQueue()->clear(true); return true; } return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface). getOption(key, val) && TerrainSceneManager::getOption(key, val); } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::getOptionValues(const String & key, StringVector &refValueList) { return TerrainSceneManager::getOptionValues( key, refValueList); } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::getOptionKeys(StringVector & refKeys) { return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface). getOptionKeys(refKeys) || TerrainSceneManager::getOptionKeys(refKeys); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::setVisibilityManager(GtpVisibility:: VisibilityManager *visManager) { mVisibilityManager = visManager; } //----------------------------------------------------------------------- GtpVisibility::VisibilityManager *OcclusionCullingSceneManager::getVisibilityManager( void ) { return mVisibilityManager; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::WriteLog() { std::stringstream d; d << "Depth pass: " << StringConverter::toString(mUseDepthPass) << ", " << "Delay transparents: " << StringConverter::toString(mDelayRenderTransparents) << ", " << "Use optimization: " << StringConverter::toString(mHierarchyInterface->GetTestGeometryForVisibleLeaves()) << ", " << "Algorithm type: " << mVisibilityManager->GetCullingManagerType() << ", " << "Hierarchy nodes: " << mNumOctants << ", " << "Traversed nodes: " << mHierarchyInterface->GetNumTraversedNodes() << ", " << "Rendered nodes: " << mHierarchyInterface->GetNumRenderedNodes() << ", " << "Query culled nodes: " << mVisibilityManager->GetCullingManager()->GetNumQueryCulledNodes() << ", " << "Frustum culled nodes: " << mVisibilityManager->GetCullingManager()->GetNumFrustumCulledNodes() << ", " << "Queries issued: " << mVisibilityManager->GetCullingManager()->GetNumQueriesIssued() << ", " << "Found objects: " << (int)mVisible.size() << "\n"; LogManager::getSingleton().logMessage(d.str()); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::renderBasicQueueGroupObjects(RenderQueueGroup* pGroup, QueuedRenderableCollection::OrganisationMode om) { // Basic render loop // Iterate through priorities RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); while (groupIt.hasMoreElements()) { RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); // Sort the queue first pPriorityGrp->sort(mCameraInProgress); // Do solids renderObjects(pPriorityGrp->getSolidsBasic(), om, true); // for correct rendering, transparents must be rendered // after hierarchical culling => don't render them now if (mNormalExecution || !mSkipTransparents) { // Do transparents (always descending) renderObjects(pPriorityGrp->getTransparents(), QueuedRenderableCollection::OM_SORT_DESCENDING, true); } } // for each priority } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::validatePassForRendering(Pass* pass) { if (mNormalExecution) { return SceneManager::validatePassForRendering(pass); } // skip all but first pass if we are doing the depth pass if ((mIsDepthPassPhase || mIsItemBufferPhase) && (pass->getIndex() > 0)) { return false; } // all but first pass /*else if ((!mIsDepthPassPhase || mIsItemBufferPhase) && (pass->getIndex() != 0)) { return false; }*/ return SceneManager::validatePassForRendering(pass); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_renderQueueGroupObjects(RenderQueueGroup* pGroup, QueuedRenderableCollection::OrganisationMode om) { if (mNormalExecution || !mIsItemBufferPhase) { TerrainSceneManager::_renderQueueGroupObjects(pGroup, om); return; } #ifdef ITEM_BUFFER //-- item buffer //-- render objects using false colors // Iterate through priorities RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); while (groupIt.hasMoreElements()) { RenderItemBuffer(groupIt.getNext()); } #endif // ITEM_BUFFER } #ifdef ITEM_BUFFER //----------------------------------------------------------------------- void OcclusionCullingSceneManager::RenderItemBuffer(RenderPriorityGroup* pGroup) { // Do solids QueuedRenderableCollection solidObjs = pGroup->getSolidsBasic();//msz // ----- SOLIDS LOOP ----- RenderPriorityGroup::SolidRenderablePassMap::const_iterator ipass, ipassend; ipassend = solidObjs.end(); for (ipass = solidObjs.begin(); ipass != ipassend; ++ipass) { // Fast bypass if this group is now empty if (ipass->second->empty()) continue; // Render only first pass of renderable as false color if (ipass->first->getIndex() > 0) continue; RenderPriorityGroup::RenderableList* rendList = ipass->second; RenderPriorityGroup::RenderableList::const_iterator irend, irendend; irendend = rendList->end(); for (irend = rendList->begin(); irend != irendend; ++irend) { if (0) { std::stringstream d; d << "itembuffer, pass name: " << ipass->first->getParent()->getParent()->getName(); LogManager::getSingleton().logMessage(d.str()); } RenderSingleObjectForItemBuffer(*irend, ipass->first); } } /////////// //-- TRANSPARENT LOOP: must be handled differently from solids // transparents are treated either as solids or completely discarded if (mRenderTransparentsForItemBuffer) { QueuedRenderableCollection transpObjs = pGroup->getTransparents(); //msz RenderPriorityGroup::TransparentRenderablePassList::const_iterator itrans, itransend; itransend = transpObjs.end(); for (itrans = transpObjs.begin(); itrans != itransend; ++itrans) { // like for solids, render only first pass if (itrans->pass->getIndex() == 0) { RenderSingleObjectForItemBuffer(itrans->renderable, itrans->pass); } } } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::RenderSingleObjectForItemBuffer(Renderable *rend, Pass *pass) { static LightList nullLightList; int col[4]; // -- create color code out of object id col[0] = (rend->getId() >> 16) & 255; col[1] = (rend->getId() >> 8) & 255; col[2] = rend->getId() & 255; // col[3] = 255; //mDestRenderSystem->setColour(col[0], col[1], col[2], col[3]); mItemBufferPass->setAmbient(ColourValue(col[0] / 255.0f, col[1] / 255.0f, col[2] / 255.0f, 1)); // set vertex program of current pass if (mExecuteVertexProgramForAllPasses && pass->hasVertexProgram()) { mItemBufferPass->setVertexProgram(pass->getVertexProgramName()); if (mItemBufferPass->hasVertexProgram()) { const GpuProgramPtr& prg = mItemBufferPass->getVertexProgram(); // Load this program if not done already if (!prg->isLoaded()) prg->load(); // Copy params mItemBufferPass->setVertexProgramParameters(pass->getVertexProgramParameters()); } } else if (mItemBufferPass->hasVertexProgram()) { mItemBufferPass->setVertexProgram(""); } const Pass *usedPass = _setPass(mItemBufferPass); // render a single object, this will set up auto params if required renderSingleObject(rend, usedPass, false, &nullLightList); } #endif // ITEM_BUFFER //----------------------------------------------------------------------- GtpVisibility::VisibilityManager *OcclusionCullingSceneManager::GetVisibilityManager() { return mVisibilityManager; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::InitVisibilityCulling(Camera *cam) { // reset culling manager stats mVisibilityManager->GetCullingManager()->InitFrame(mVisualizeCulledNodes); // set depth pass flag before rendering mIsDepthPassPhase = mUseDepthPass; // indicates that we use hierarchical culling from now on mIsHierarchicalCulling = true; // item buffer needs full ambient lighting to use item colors as unique id if (mUseItemBuffer) { mIsItemBufferPhase = true; setAmbientLight(ColourValue(1,1,1,1)); } // set passes which are stored in render queue // for rendering AFTER hierarchical culling, i.e., passes which need // a special rendering order mLeavePassesInQueue = 0; // if we have the depth pass or use an item buffer, we leave no passes in the queue if (1 && !mUseDepthPass && !mUseItemBuffer) { if (mShadowTechnique == SHADOWTYPE_STENCIL_ADDITIVE) { // TODO: remove this pass because it should be processed during hierarchical culling //mLeavePassesInQueue |= RenderPriorityGroup::SOLID_PASSES_NOSHADOW; mLeavePassesInQueue |= RenderPriorityGroup::SOLID_PASSES_DECAL; mLeavePassesInQueue |= RenderPriorityGroup::SOLID_PASSES_DIFFUSE_SPECULAR; mLeavePassesInQueue |= RenderPriorityGroup::TRANSPARENT_PASSES; // just render ambient passes /*** msz: no more IRS_AMBIENT, see OgreSceneManager.h ***/ // mIlluminationStage = IRS_AMBIENT; //getRenderQueue()->setSplitPassesByLightingType(true); } if (mShadowTechnique == SHADOWTYPE_STENCIL_MODULATIVE) { mLeavePassesInQueue |= RenderPriorityGroup::SOLID_PASSES_NOSHADOW; mLeavePassesInQueue |= RenderPriorityGroup::TRANSPARENT_PASSES; } // transparents should be rendered after hierarchical culling to // provide front-to-back ordering if (mDelayRenderTransparents) { mLeavePassesInQueue |= RenderPriorityGroup::TRANSPARENT_PASSES; } } // skip rendering transparents during the hierarchical culling // (because they will be rendered afterwards) mSkipTransparents = (mIsDepthPassPhase || (mLeavePassesInQueue & RenderPriorityGroup::TRANSPARENT_PASSES)); // -- initialise interface for rendering traversal of the hierarchy mHierarchyInterface->SetHierarchyRoot(mOctree); // possible two cameras (one for culling, one for rendering) mHierarchyInterface->InitTraversal(mCameraInProgress, mCullCamera ? getCamera("CullCamera") : NULL, mLeavePassesInQueue); } //----------------------------------------------------------------------- OctreeHierarchyInterface *OcclusionCullingSceneManager::GetHierarchyInterface() { return mHierarchyInterface; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::endFrame() { TerrainRenderable::ResetRenderLevelIndex(); } //----------------------------------------------------------------------- Entity* OcclusionCullingSceneManager::createEntity(const String& entityName, const String& meshName) { Entity *ent = SceneManager::createEntity(entityName, meshName); for (int i = 0; i < (int)ent->getNumSubEntities(); ++i) { ent->getSubEntity(i)->setId(mCurrentEntityId); } // increase counter of entity id values ++ mCurrentEntityId; return ent; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::renderAdditiveStencilShadowedQueueGroupObjects( RenderQueueGroup* pGroup, QueuedRenderableCollection::OrganisationMode om) { // only render solid passes during hierarchical culling if (mIsHierarchicalCulling) { RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); LightList lightList; while (groupIt.hasMoreElements()) { RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); // Sort the queue first pPriorityGrp->sort(mCameraInProgress); // Clear light list lightList.clear(); // Render all the ambient passes first, no light iteration, no lights /*** msz: no more IRS_AMBIENT, see OgreSceneManager.h ***/ // mIlluminationStage = IRS_AMBIENT; OctreeSceneManager::renderObjects(pPriorityGrp->getSolidsBasic(), om, false, &lightList); // Also render any objects which have receive shadows disabled OctreeSceneManager::renderObjects(pPriorityGrp->getSolidsNoShadowReceive(), om, true); #if 0 std::stringstream d; d << " solid size: " << (int)pPriorityGrp->_getSolidPasses().size() << " solid no shadow size: " << (int)pPriorityGrp->_getSolidPassesNoShadow().size() << "difspec size: " << (int)pPriorityGrp->_getSolidPassesDiffuseSpecular().size() << " decal size: " << (int)pPriorityGrp->_getSolidPassesDecal().size(); LogManager::getSingleton().logMessage(d.str()); #endif } } else // render the rest of the passes { OctreeSceneManager::renderAdditiveStencilShadowedQueueGroupObjects(pGroup, om); } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::renderModulativeStencilShadowedQueueGroupObjects( RenderQueueGroup* pGroup, QueuedRenderableCollection::OrganisationMode om) { if (mIsHierarchicalCulling) { // Iterate through priorities RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); while (groupIt.hasMoreElements()) { RenderPriorityGroup* pPriorityGrp = groupIt.getNext(); // Sort the queue first pPriorityGrp->sort(mCameraInProgress); // Do (shadowable) solids OctreeSceneManager::renderObjects(pPriorityGrp->getSolidsBasic(), om, true); } } else { OctreeSceneManager::renderModulativeStencilShadowedQueueGroupObjects(pGroup, om); } } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::SetObjectsVisible(const bool visible) { GtpVisibilityPreprocessor::ObjectContainer::iterator it, it_end = mObjects.end(); for (it = mObjects.begin(); it != it_end; ++ it) { GtpVisibilityPreprocessor::Intersectable *entry = *it; SetObjectVisible(entry, visible); } } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::LoadViewCells(const String &filename) { // no filename specified if (filename == "") return false; // view cells already loaded if (mViewCellsLoaded) return true; // converter between view cell ids and Ogre entites OctreeBoundingBoxConverter bconverter(this); // load the view cells assigning the found objects to the pvss const bool finalizeViewCells = false; // load the view cells assigning the found objects to the pvss mViewCellsManager = GtpVisibilityPreprocessor::ViewCellsManager:: LoadViewCells(filename, mObjects, false, &bconverter); Ogre::LogManager::getSingleton().logMessage("******** view cells loaded *********"); // objects are set to invisible initially SetObjectsVisible(false); if (finalizeViewCells) { CreateViewCellsGeometry(); } return (mViewCellsManager != NULL); } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::ApplyViewCellPvs(GtpVisibilityPreprocessor::ViewCell *vc, const bool load) { // NOTE: should not encounter NULL view cell, // rather apply view cell representing unbounded space then if (!vc) { LogManager::getSingleton().logMessage("error: should not come here"); // question: if no view cell, set everything visible? //SetObjectsVisible(true); SetObjectsVisible(false); return; } //////////// //-- set PVS of view cell to visible //std::stringstream d; d << "appying new view cell pvs: " << vc->GetPvs().GetSize(); //LogManager::getSingleton().logMessage(d.str()); GtpVisibilityPreprocessor::ObjectPvsIterator pit = vc->GetPvs().GetIterator(); while (pit.HasMoreEntries()) { GtpVisibilityPreprocessor::Intersectable *obj = pit.Next(); // no associated geometry found if (!obj) continue; SetObjectVisible(obj, load); } } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::UpdatePvs(Camera *cam) { if (!(mViewCellsLoaded && mUseViewCells)) return; const GtpVisibilityPreprocessor::Vector3 viewPoint = OgreTypeConverter::ConvertFromOgre(cam->getDerivedPosition()); //std::stringstream d; d << "vp: " << viewPoint; //LogManager::getSingleton().logMessage(d.str()); GtpVisibilityPreprocessor::ViewCell *newElementary = mViewCellsManager->GetViewCell(viewPoint); // elementary view cell did not change => don't change pvs if (mElementaryViewCell == newElementary) return; mElementaryViewCell = newElementary; ////////////// //-- unload old pvs ApplyViewCellPvs(mCurrentViewCell, false); // the new view cell GtpVisibilityPreprocessor::ViewCell *viewCell; if (mUseVisibilityFilter) { //////////// //-- compute new filtered cell GtpVisibilityPreprocessor::PrVs prvs; mViewCellsManager->GetPrVS(viewPoint, prvs, 5); viewCell = prvs.mViewCell; } else { viewCell = newElementary; } /////////////// //-- load new pvs ApplyViewCellPvs(viewCell, true); if (viewCell) { // store current view cell mCurrentViewCell->SetPvs(viewCell->GetPvs()); mCurrentViewCell->SetMesh(viewCell->GetMesh()); mCurrentViewCell->SetId(viewCell->GetId()); // delete merge tree of filtered view cell if (mUseVisibilityFilter) mViewCellsManager->DeleteLocalMergeTree(viewCell); } } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::CreateViewCellsGeometry() { //LogManager::getSingleton().logMessage("creating view cells geometry"); if (mViewCellsGeometryLoaded) return; GtpVisibilityPreprocessor::ViewCellContainer viewCells = mViewCellsManager->GetViewCells(); GtpVisibilityPreprocessor::ViewCellContainer::const_iterator it, it_end = viewCells.end(); for (it = viewCells.begin(); it != it_end; ++ it) { GtpVisibilityPreprocessor::ViewCell *viewCell = *it; ManualObject *manual = OgreTypeConverter::ConvertToOgre(viewCell->GetMesh(), this); if (manual) { mViewCellsGeometry[viewCell->GetId()] = manual; // attach to scene node getRootSceneNode()->createChildSceneNode()->attachObject(manual); manual->setQueryFlags(0); // returned by no query // initialy set to invisible manual->setVisible(false); } } mViewCellsGeometryLoaded = true; } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::VisualizeViewCells(const bool visualize) { MovableMap::const_iterator mit, mit_end = mViewCellsGeometry.end(); for (mit = mViewCellsGeometry.begin(); mit != mit_end; ++ mit) { if ((*mit).second) (*mit).second->setVisible(visualize); } } #if 0 //------------------------------------------------------------------------- void OcclusionCullingSceneManager::TestVisible(SceneNode *node) { // first test for scene node, then for octant (part of the hierarchy) if (!node->mVisibleChildren) { node->setVisible(false); } node->getOctant()->mVisibleChildren --; } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::TestVisible(Octree *octant) { // first test for scene node, then for octant (part of the hierarchy) if (!octant->mVisibleChildren) { octant->setVisible(false); } } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::UpdateVisibility(Entity *ent) { if (!ent->isVisible()) { bool visible = TestVisible(ent->getParentNode()); if (!visible) visible = TestVisible(octant->getParentNode()); if (!visible) mHierarchyInterface->pullupVisibility(); } } #endif // splits strings containing multiple file names static int SplitFilenames(const std::string str, std::vector &filenames) { int pos = 0; while(1) { int npos = (int)str.find(';', pos); if (npos < 0 || npos - pos < 1) break; filenames.push_back(std::string(str, pos, npos - pos)); pos = npos + 1; } filenames.push_back(std::string(str, pos, str.size() - pos)); return (int)filenames.size(); } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::LoadScene(const String &filename, const String &viewCellsFilename) { using namespace std; // use leaf nodes of the original spatial hierarchy as occludees vector filenames; const int files = SplitFilenames(filename, filenames); stringstream d; d << "number of input files: " << files << "\n"; LogManager::getSingleton().logMessage(d.str()); bool result = false; vector::const_iterator fit, fit_end = filenames.end(); int i = 0; if (filename == "terrain") { LogManager::getSingleton().logMessage("loading terrain"); // terrain hack return false; } for (fit = filenames.begin(); fit != fit_end; ++ fit, ++ i) { const string fn = *fit; if (strstr(fn.c_str(), ".obj")) { // load iv files if (!LoadSceneObj(filename, viewCellsFilename, getRootSceneNode())) { LogManager::getSingleton().logMessage("error loading file"); return false; } } else if (strstr(fn.c_str(), ".iv") || strstr(fn.c_str(), ".wrl")) { // load iv files if (!LoadSceneIV(fn, getRootSceneNode(), i)) { // terrain hack LogManager::getSingleton().logMessage("error loading file"); } } // at least one piece of geometry loaded result = true; } return result; } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::LoadSceneIV(const String &filename, SceneNode *root, const int index) { IVReader ivReader; Timer *timer = PlatformManager::getSingleton().createTimer(); timer->reset(); if (1) { std::string logFilename = "IVLog" + Ogre::StringConverter().toString(index) + ".log"; Log *log = LogManager::getSingleton().createLog(logFilename); ivReader.setLog(log); } //viennaNode->translate(Vector3(-300, -300, 0)); if (ivReader.loadFile(filename.c_str())) { SceneNode *node = root->createChildSceneNode("IVSceneNode" + index); ivReader.buildTree(this, node); ivReader.collapse(); std::stringstream d; d << "loaded " << filename << " in " << timer->getMilliseconds() * 1e-3 << " secs"; LogManager::getSingleton().logMessage(d.str()); PlatformManager::getSingleton().destroyTimer(timer); //-- bake into static geometry /*if (USE_STATIC_GEOMETRY) { BakeSceneIntoStaticGeometry("staticVienna", "Vienna"); }*/ return true; } return false; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::RenderDepthPass() { // create material for depth pass InitDepthPass(); //////////////////// //-- hierarchical culling // set all necessary parameters for // hierarchical visibility culling and rendering InitVisibilityCulling(mCameraInProgress); /** * the hierarchical culling algorithm * for depth pass: we just find objects and update depth buffer * for "delayed" rendering: we render some passes afterwards * e.g., transparents, because they need front-to-back sorting **/ mVisibilityManager->ApplyVisibilityCulling(); // delete remaining renderables from queue: // all which are not in mLeavePassesInQueue) _deleteRenderedQueueGroups(mLeavePassesInQueue); ///////////// //-- reset parameters needed for special rendering mIsDepthPassPhase = false; mIsItemBufferPhase = false; mSkipTransparents = false; mIsHierarchicalCulling = false; mLeavePassesInQueue = 0; // the shaded geometry is rendered in a second pass // add visible nodes found by the visibility culling algorithm NodeList::const_iterator it, it_end = mVisible.end(); if(1) for (it = mVisible.begin(); it != it_end; ++ it) { (*it)->_addToRenderQueue(mCameraInProgress, getRenderQueue(), false); } } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::LoadSceneObj(const String &filename, const String &viewCellsFile, SceneNode *root) { Timer *timer = PlatformManager::getSingleton().createTimer(); timer->reset(); if (!mObjReader->LoadFile(filename.c_str(), viewCellsFile, root)) { PlatformManager::getSingleton().destroyTimer(timer); return false; } std::stringstream d; d << "loaded " << filename << " in " << timer->getMilliseconds() * 1e-3 << " secs"; LogManager::getSingleton().logMessage(d.str()); PlatformManager::getSingleton().destroyTimer(timer); return true; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_renderScene(Camera* camera, Viewport* vp, bool includeOverlays) { Root::getSingleton()._setCurrentSceneManager(this); mActiveQueuedRenderableVisitor->targetSceneMgr = this; if (isShadowTechniqueInUse()) { // Prepare shadow materials initShadowVolumeMaterials(); } // Perform a quick pre-check to see whether we should override far distance // When using stencil volumes we have to use infinite far distance // to prevent dark caps getting clipped if (isShadowTechniqueStencilBased() && camera->getProjectionType() == PT_PERSPECTIVE && camera->getFarClipDistance() != 0 && mDestRenderSystem->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE) && mShadowUseInfiniteFarPlane) { // infinite far distance camera->setFarClipDistance(0); } mCameraInProgress = camera; // Update controllers ControllerManager::getSingleton().updateAllControllers(); // Update the scene, only do this once per frame unsigned long thisFrameNumber = Root::getSingleton().getCurrentFrameNumber(); if (thisFrameNumber != mLastFrameNumber) { // Update animations _applySceneAnimations(); mLastFrameNumber = thisFrameNumber; } // Update scene graph for this camera (can happen multiple times per frame) _updateSceneGraph(camera); // Auto-track nodes AutoTrackingSceneNodes::iterator atsni, atsniend; atsniend = mAutoTrackingSceneNodes.end(); for (atsni = mAutoTrackingSceneNodes.begin(); atsni != atsniend; ++atsni) { (*atsni)->_autoTrack(); } // Auto-track camera if required camera->_autoTrack(); // Are we using any shadows at all? if (isShadowTechniqueInUse() && mIlluminationStage != IRS_RENDER_TO_TEXTURE && vp->getShadowsEnabled() && mFindVisibleObjects) { // Locate any lights which could be affecting the frustum findLightsAffectingFrustum(camera); if (isShadowTechniqueTextureBased()) { // ******* // WARNING // ******* // This call will result in re-entrant calls to this method // therefore anything which comes before this is NOT // guaranteed persistent. Make sure that anything which // MUST be specific to this camera / target is done // AFTER THIS POINT prepareShadowTextures(camera, vp); // reset the cameras because of the re-entrant call mCameraInProgress = camera; } } // Invert vertex winding? if (camera->isReflected()) { mDestRenderSystem->setInvertVertexWinding(true); } else { mDestRenderSystem->setInvertVertexWinding(false); } // Tell params about viewport mAutoParamDataSource.setCurrentViewport(vp); // Set the viewport setViewport(vp); // Tell params about camera mAutoParamDataSource.setCurrentCamera(camera); // Set autoparams for finite dir light extrusion mAutoParamDataSource.setShadowDirLightExtrusionDistance(mShadowDirLightExtrudeDist); // Tell params about current ambient light mAutoParamDataSource.setAmbientLightColour(mAmbientLight); // Tell rendersystem mDestRenderSystem->setAmbientLight(mAmbientLight.r, mAmbientLight.g, mAmbientLight.b); // Tell params about render target mAutoParamDataSource.setCurrentRenderTarget(vp->getTarget()); // Set camera window clipping planes (if any) if (mDestRenderSystem->getCapabilities()->hasCapability(RSC_USER_CLIP_PLANES)) { if (camera->isWindowSet()) { const std::vector& planeList = camera->getWindowPlanes(); for (ushort i = 0; i < 4; ++i) { mDestRenderSystem->enableClipPlane(i, true); mDestRenderSystem->setClipPlane(i, planeList[i]); } } else { for (ushort i = 0; i < 4; ++i) { mDestRenderSystem->enableClipPlane(i, false); } } } // Prepare render queue for receiving new objects prepareRenderQueue(); mDestRenderSystem->_beginGeometryCount(); // Begin the frame mDestRenderSystem->_beginFrame(); // Set rasterisation mode mDestRenderSystem->_setPolygonMode(camera->getPolygonMode()); // Set initial camera state mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS()); mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix(true)); if (mFindVisibleObjects) { // Parse the scene and tag visibles myFindVisibleObjects(camera, mIlluminationStage == IRS_RENDER_TO_TEXTURE? true : false); } // Add overlays, if viewport deems it if (vp->getOverlaysEnabled() && mIlluminationStage != IRS_RENDER_TO_TEXTURE) { OverlayManager::getSingleton()._queueOverlaysForRendering(camera, getRenderQueue(), vp); } // Queue skies, if viewport seems it if (vp->getSkiesEnabled() && mFindVisibleObjects && mIlluminationStage != IRS_RENDER_TO_TEXTURE) { _queueSkiesForRendering(camera); } // Render scene content _renderVisibleObjects(); // End frame mDestRenderSystem->_endFrame(); // Notify camera or vis faces camera->_notifyRenderedFaces(mDestRenderSystem->_getFaceCount()); } //----------------------------------------------------------------------- const String OcclusionCullingSceneManagerFactory::FACTORY_TYPE_NAME = "OcclusionCullingSceneManager"; //----------------------------------------------------------------------- void OcclusionCullingSceneManagerFactory::initMetaData(void) const { mMetaData.typeName = FACTORY_TYPE_NAME; mMetaData.description = "Scene manager organising the scene on the basis of an octree with advanced occlusion culling (TM)."; mMetaData.sceneTypeMask = 0xFFFF; // support all types mMetaData.worldGeometrySupported = false; } //----------------------------------------------------------------------- SceneManager *OcclusionCullingSceneManagerFactory::createInstance( const String& instanceName) { OcclusionCullingSceneManager* tsm = new OcclusionCullingSceneManager(instanceName, visManager); // Create & register default sources (one per manager) HeightmapTerrainPageSource* ps = new HeightmapTerrainPageSource(); mTerrainPageSources.push_back(ps); tsm->registerPageSource("Heightmap", ps); return tsm; } //----------------------------------------------------------------------- void OcclusionCullingSceneManagerFactory::destroyInstance(SceneManager* instance) { delete instance; } } // namespace Ogre