#include "OgreOcclusionCullingSceneManager.h" #include "OgreVisibilityOptionsManager.h" #include "OgreTypeConverter.h" #include #include #include #include #include #include #include #include #include #include "VspBspTree.h" #include "Containers.h" #include "ViewCellsManager.h" namespace Ogre { //----------------------------------------------------------------------- OcclusionCullingSceneManager::OcclusionCullingSceneManager( GtpVisibility::VisibilityManager *visManager): mVisibilityManager(visManager), mShowVisualization(false), mRenderNodesForViz(false), mRenderNodesContentForViz(false), mVisualizeCulledNodes(false), mLeavePassesInQueue(0), mDelayRenderTransparents(true), mUseDepthPass(false), mIsDepthPassPhase(false), mUseItemBuffer(false), //mUseItemBuffer(true), mIsItemBufferPhase(false), mCurrentEntityId(1), mEnableDepthWrite(true), mSkipTransparents(false), mRenderTransparentsForItemBuffer(true), mExecuteVertexProgramForAllPasses(true), mIsHierarchicalCulling(false) { mHierarchyInterface = new OctreeHierarchyInterface(this, mDestRenderSystem); #if 0 mDisplayNodes = true; mShowBoundingBoxes = true; mShowBoxes = true; #endif // TODO: set maxdepth to reasonable value mMaxDepth = 50; } //----------------------------------------------------------------------- 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); } //----------------------------------------------------------------------- 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); } //------------------------------------------------------------------------- void OcclusionCullingSceneManager::setWorldGeometry( const String& filename ) { // Clear out any existing world resources (if not default) if (ResourceGroupManager::getSingleton().getWorldResourceGroupName() != ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) { ResourceGroupManager::getSingleton().clearResourceGroup( ResourceGroupManager::getSingleton().getWorldResourceGroupName()); } mTerrainPages.clear(); // Load the configuration loadConfig(filename); // Resize the octree, allow for 1 page for now float max_x = mOptions.scale.x * mOptions.pageSize; float max_y = mOptions.scale.y; 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 ) ); setupTerrainMaterial(); setupTerrainPages(); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::PrepareVisualization(Camera *cam) { // add player camera for visualization purpose try { Camera *c; if ((c = getCamera("PlayerCam")) != NULL) { getRenderQueue()->addRenderable(c); } } catch (...) { // ignore } for (BoxList::iterator it = mBoxes.begin(); it != mBoxes.end(); ++it) { getRenderQueue()->addRenderable(*it); } 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 leaf nodes if (((*it)->numAttachedObjects() > 0) && ((*it)->numChildren() == 0) && (*it)->getAttachedObject(0)->getMovableType() == "Entity") { getRenderQueue()->addRenderable((*it)); } // addbounding boxes instead of node itself //(*it)->_addBoundingBoxToQueue(getRenderQueue()); } if (mRenderNodesContentForViz) { (*it)->_addToRenderQueue(cam, getRenderQueue(), false); } } } } //----------------------------------------------------------------------- Pass *OcclusionCullingSceneManager::setPass(Pass* 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 Pass *usedPass = (mIsDepthPassPhase && !mHierarchyInterface->IsBoundingBoxQuery() ? mDepthPass : pass); IlluminationRenderStage savedStage = mIlluminationStage; // 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()) { mDepthPass->setVertexProgram(""); } bool IsDepthWrite = usedPass->getDepthWriteEnabled(); // global option which enables / disables depth writes if (!mEnableDepthWrite) { usedPass->setDepthWriteEnabled(false); } //else if (mIsItemBufferPass) {usedPass = mItemBufferPass;} Pass *result = SceneManager::setPass(usedPass); // reset depth write if (!mEnableDepthWrite) { usedPass->setDepthWriteEnabled(IsDepthWrite); } // reset illumination stage mIlluminationStage = savedStage; return result; } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters) { //-- show visible scene nodes and octree bounding boxes from last frame if (mShowVisualization) { PrepareVisualization(cam); } else { // for hierarchical culling, we interleave identification // and rendering of objects in _renderVisibibleObjects // for the shadow pass we use only standard rendering // because of low occlusion if (mShadowTechnique == SHADOWTYPE_TEXTURE_MODULATIVE && mIlluminationStage == IRS_RENDER_TO_TEXTURE) { TerrainSceneManager::_findVisibleObjects(cam, onlyShadowCasters); } // only shadow casters will be rendered in shadow texture pass // mHierarchyInterface->SetOnlyShadowCasters(onlyShadowCasters); } // -- delete lists stored for visualization mVisible.clear(); mBoxes.clear(); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_renderVisibleObjects() { InitDepthPass(); // create material for depth pass InitItemBufferPass(); // create material for item buffer pass // save ambient light to reset later ColourValue savedAmbient = mAmbientLight; //-- apply standard rendering for some modes (e.g., visualization, shadow pass) if (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 { // don't render backgrounds for item buffer if (mUseItemBuffer) { clearSpecialCaseRenderQueues(); getRenderQueue()->clear(); } //-- hierarchical culling // the objects of different layers (e.g., background, scene, // overlay) must be identified and rendered one after another //-- 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 this 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 not in mLeavePassesInQueue) #ifdef GTP_VISIBILITY_MODIFIED_OGRE _deleteRenderedQueueGroups(mLeavePassesInQueue); #endif //-- reset parameters mIsDepthPassPhase = false; mIsItemBufferPhase = false; mSkipTransparents = false; mLeavePassesInQueue = 0; // add visible nodes found by the visibility culling algorithm if (mUseDepthPass) { for (NodeList::iterator it = mVisible.begin(); it != mVisible.end(); ++ it) { (*it)->_addToRenderQueue(mCameraInProgress, getRenderQueue(), false); } } //-- now we can render all remaining queue objects // used for depth pass, transparents, overlay clearSpecialCaseRenderQueues(); TerrainSceneManager::_renderVisibleObjects(); } // HACK: set the new render level index, important to avoid cracks // in terrain caused by LOD TerrainRenderable::NextRenderLevelIndex(); // reset ambient light setAmbientLight(savedAmbient); getRenderQueue()->clear(); // finally clear render queue OGRE_DELETE(mRenderQueue); // HACK: should be cleared before ... WriteLog(); // write out stats } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::_updateSceneGraph(Camera* cam) { 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") { 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; } if (key == "NodeVizScale") { OctreeNode::setVizScale(*static_cast(val)); return true; } if (key == "UseArbQueries") { bool useArbQueries = (*static_cast(val)); if (useArbQueries) { mHierarchyInterface->DeleteQueries(); mDestRenderSystem->setConfigOption("ArbQueries", "Yes"); } else { mHierarchyInterface->DeleteQueries(); mDestRenderSystem->setConfigOption("ArbQueries", "No"); } } 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; } 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() << "\n"; LogManager::getSingleton().logMessage(d.str()); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::renderObjects( const RenderPriorityGroup::TransparentRenderablePassList& objs, bool doLightIteration, const LightList* manualLightList) { // for correct rendering, transparents must be rendered after hierarchical culling if (!mSkipTransparents) { OctreeSceneManager::renderObjects(objs, doLightIteration, manualLightList); } } //----------------------------------------------------------------------- bool OcclusionCullingSceneManager::validatePassForRendering(Pass* pass) { // skip all but first pass if we are doing the depth pass if ((mIsDepthPassPhase || mIsItemBufferPhase) && pass->getIndex() > 0) { return false; } return SceneManager::validatePassForRendering(pass); } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::renderQueueGroupObjects(RenderQueueGroup* pGroup) { if (!mIsItemBufferPhase) { TerrainSceneManager::renderQueueGroupObjects(pGroup); return; } //-- item buffer // Iterate through priorities RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); while (groupIt.hasMoreElements()) { RenderItemBuffer(groupIt.getNext()); } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::RenderItemBuffer(RenderPriorityGroup* pGroup) { // Do solids RenderPriorityGroup::SolidRenderablePassMap solidObjs = pGroup->_getSolidPasses(); // ----- 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 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) { //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 // transparents are treated either as solids or completely discarded if (mRenderTransparentsForItemBuffer) { RenderPriorityGroup::TransparentRenderablePassList transpObjs = pGroup->_getTransparentPasses(); 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(""); } Pass *usedPass = setPass(mItemBufferPass); // Render a single object, this will set up auto params if required renderSingleObject(rend, usedPass, false, &nullLightList); } //----------------------------------------------------------------------- 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; // 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, no passes are left in the queue if (0 && !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 stuff mIlluminationStage = IRS_AMBIENT; } 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 in the hierarchical culling // (because they will be rendered afterwards) mSkipTransparents = mUseDepthPass || (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) { // 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 mIlluminationStage = IRS_AMBIENT; OctreeSceneManager::renderObjects(pPriorityGrp->_getSolidPasses(), false, &lightList); // Also render any objects which have receive shadows disabled OctreeSceneManager::renderObjects(pPriorityGrp->_getSolidPassesNoShadow(), true); } } else { OctreeSceneManager::renderAdditiveStencilShadowedQueueGroupObjects(pGroup); } } //----------------------------------------------------------------------- void OcclusionCullingSceneManager::renderModulativeStencilShadowedQueueGroupObjects(RenderQueueGroup* pGroup) { 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->_getSolidPasses(), true); } } else { SceneManager::renderModulativeStencilShadowedQueueGroupObjects(pGroup); } } MovableObject *OcclusionCullingSceneManager::FindCorrespondingObject(const AxisAlignedBox &box) { list sceneNodeList; findNodesIn(box, sceneNodeList, NULL); list::const_iterator sit, sit_end = sceneNodeList.end(); bool overlap = false; MovableObject *bestFittingObj = NULL; float bestFit = 0.0; // find the bbox which is closest to the current bbox for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(), !overlap; ++ sit) { SceneNode *sn = *sit; SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator(); while (oit.hasMoreElements()) { MovableObject *mo = oit.getNext(); const AxisAlignedBox bbox = mo->getWorldBoundingBox(); const float overlap = GtpVisibilityPreprocessor::FactorOfOverlap( OgreTypeConverter::ConvertFromOgre(bbox), OgreTypeConverter::ConvertFromOgre(box)); if (overlap > bestFit) { bestFit = overlap; bestFittingObj = mo; // perfect fit => object found if (overlap > (1.0 - GtpVisibilityPreprocessor::Limits::Small)) break; } } } return bestFittingObj; } void OcclusionCullingSceneManager::LoadViewCells(string filename) { GtpVisibilityPreprocessor::ObjectContainer objects; // identify the corresponding Ogre meshes using the bounding boxes IdentifyObjects(objects); // load the view cells assigning the found objects to the pvss mViewCellsManager->LoadViewCells(filename, &objects); } void OcclusionCullingSceneManager::IdentifyObjects(GtpVisibilityPreprocessor::ObjectContainer &objects) { const string bboxesFilename = "boxes.out"; GtpVisibilityPreprocessor::IndexedBoundingBoxContainer iboxes; mViewCellsManager->LoadBoundingBoxes(bboxesFilename, iboxes); GtpVisibilityPreprocessor::IndexedBoundingBoxContainer:: const_iterator iit, iit_end = iboxes.end(); for (iit = iboxes.begin(); iit != iit_end; ++ iit) { const GtpVisibilityPreprocessor::AxisAlignedBox3 box = (*iit).second; const AxisAlignedBox currentBox = OgreTypeConverter::ConvertToOgre(box); MovableObject *mo = FindCorrespondingObject(currentBox); //objects.push_back(mi); } } } // namespace Ogre