#include "OgreVisibilityTerrainSceneManager.h" #include "OgreVisibilityOptionsManager.h" #include #include #include #include #include #include #include #include namespace Ogre { //----------------------------------------------------------------------- VisibilityTerrainSceneManager::VisibilityTerrainSceneManager( GtpVisibility::VisibilityManager *visManager): mVisibilityManager(visManager), mRenderDepthPass(false), mShowVisualization(false), mRenderNodesForViz(false), mRenderNodesContentForViz(false), mVisualizeCulledNodes(false), mSkipTransparents(false), mDelayRenderTransparents(true), mUseDepthPass(false), mRenderItemBuffer(false), mCurrentEntityId(0), mEnableDepthWrite(true) { mHierarchyInterface = new OctreeHierarchyInterface(this, mDestRenderSystem); mQueryManager = new PlatformQueryManager(mHierarchyInterface, mCurrentViewport); mVisibilityManager->SetQueryManager(mQueryManager); //mDisplayNodes = true; //mShowBoundingBoxes = true; // TODO: set maxdepth to reasonable value mMaxDepth = 50; } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::InitDepthPass() { MaterialPtr depthMat = MaterialManager::getSingleton().getByName("Visibility/DepthPass"); if (depthMat.isNull()) { // Init 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); } } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::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); } else { mItemBufferPass = itemBufferMat->getTechnique(0)->getPass(0); } mItemBufferPass->setAmbient(1, 1, 0); } //----------------------------------------------------------------------- VisibilityTerrainSceneManager::~VisibilityTerrainSceneManager() { if (mHierarchyInterface) { delete mHierarchyInterface; mHierarchyInterface = NULL; } if (mQueryManager) { delete mQueryManager; mQueryManager = NULL; } } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::ShowVisualization(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) { // 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) { getRenderQueue()->addRenderable(*it); // addbounding boxes instead of node itself //(*it)->_addBoundingBoxToQueue(getRenderQueue()); } if (mRenderNodesContentForViz) { (*it)->_addToRenderQueue(cam, getRenderQueue(), false); } } } } //----------------------------------------------------------------------- Pass *VisibilityTerrainSceneManager::setPass(Pass* pass) { //Pass *usedPass = ((mRenderDepthPass && !pass->hasVertexProgram()) ? mDepthPass : pass); // setting vertex program is not efficient // set depth fill pass only if depth write enabled Pass *usedPass = (mRenderDepthPass && !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 (mRenderDepthPass || mHierarchyInterface->IsBoundingBoxQuery()) { mIlluminationStage = IRS_NONE; } if (mRenderDepthPass) { // --- set vertex program of current pass so z-buffer is updated correctly if (pass->hasVertexProgram()) { 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 VisibilityTerrainSceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters) { // needs full ambient lighting for item colors to be exact /*if (mRenderItemBuffer) { setAmbientLight(ColourValue(1,1,1,1)); }*/ //-- show visible scene nodes and octree bounding boxes from last frame if (mShowVisualization) { ShowVisualization(cam); } //TerrainSceneManager::_findVisibleObjects(cam, onlyShadowCasters); mVisible.clear(); mBoxes.clear(); // if there is no depth pass => // we interleave identification and rendering of objects // in _renderVisibibleObjects // only shadow casters will be rendered in shadow texture pass mHierarchyInterface->SetOnlyShadowCasters(onlyShadowCasters); bool leaveTransparentsInQueue = mDelayRenderTransparents && !mUseDepthPass; // possible two cameras (one for culling, one for rendering) mHierarchyInterface->InitFrame(mOctree, cam, //mCameraInProgress, mCullCamera ? getCamera("CullCamera") : NULL, leaveTransparentsInQueue); } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::_renderVisibleObjects() { // increase terrain renderlevel int renderLevel = TerrainRenderable::getCurrentRenderLevelIndex() + 1; if (TerrainRenderable::getCurrentRenderLevelIndex() >= 10) { // max. 10 different renderlevels renderLevel = 0; } // visualization: apply standard rendering if (mShowVisualization) { TerrainSceneManager::_renderVisibleObjects(); TerrainRenderable::setCurrentRenderLevelIndex(renderLevel); return; } InitDepthPass(); // create material for depth pass InitItemBufferPass(); // create material for item buffer pass //-- hierarchical culling // the objects of different layers (e.g., background, scene, // overlay) must be identified and rendered one after another // frame initialisation to reset culling manager stats mVisibilityManager->GetCullingManager()->InitFrame(mVisualizeCulledNodes); mSkipTransparents = false; //-- render background, in case there is one clearSpecialCaseRenderQueues(); addSpecialCaseRenderQueue(RENDER_QUEUE_BACKGROUND); addSpecialCaseRenderQueue(RENDER_QUEUE_SKIES_EARLY); setSpecialCaseRenderQueueMode(SceneManager::SCRQM_INCLUDE); TerrainSceneManager::_renderVisibleObjects(); #ifdef GTP_VISIBILITY_MODIFIED_OGRE _deleteRenderedQueueGroups(false); #endif //-- render visible objects (i.e., all but overlay and skies late) clearSpecialCaseRenderQueues(); addSpecialCaseRenderQueue(RENDER_QUEUE_SKIES_LATE); addSpecialCaseRenderQueue(RENDER_QUEUE_OVERLAY); setSpecialCaseRenderQueueMode(SceneManager::SCRQM_EXCLUDE); // transparents are skipped from hierarchical rendering // => they need sorting, thus we render them afterwards mSkipTransparents = mDelayRenderTransparents; // set state for depth pass mRenderDepthPass = mUseDepthPass; /** * the hierarchical culling algorithm * for depth pass: will just find objects and update depth buffer * for delayed rendering: will render all but transparents **/ mVisibilityManager->ApplyVisibilityCulling(); // delete remaining renderables from queue (or all but transparents) #ifdef GTP_VISIBILITY_MODIFIED_OGRE _deleteRenderedQueueGroups(mSkipTransparents); #endif // for depth pass: add visible nodes found with the visibility culling if (mUseDepthPass) { for (NodeList::iterator it = mVisible.begin(); it != mVisible.end(); ++it) { (*it)->_addToRenderQueue(mCameraInProgress, getRenderQueue(), false); } mRenderDepthPass = false; } mSkipTransparents = false; //-- now we can render all remaining queue objects // for depth pass: all // for delayed rendering: transparents, overlay clearSpecialCaseRenderQueues(); TerrainSceneManager::_renderVisibleObjects(); TerrainRenderable::setCurrentRenderLevelIndex(renderLevel); getRenderQueue()->clear(); //WriteLog(); // write out stats } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::_updateSceneGraph(Camera* cam) { mVisibilityManager->GetCullingManager()->SetHierarchyInterface(mHierarchyInterface); mHierarchyInterface->SetRenderSystem(mDestRenderSystem); #ifdef GTP_VISIBILITY_MODIFIED_OGRE mHierarchyInterface->SetNumOctreeNodes(mNumOctreeNodes); #endif TerrainSceneManager::_updateSceneGraph(cam); } //----------------------------------------------------------------------- bool VisibilityTerrainSceneManager::setOption(const String & key, const void * val) { if (key == "UseDepthPass") { mUseDepthPass = (*static_cast(val)); return true; } if (key == "ShowVisualization") { 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; } // notifiy that frame has ended so terrain render level can be reset for correct // terrain rendering if (key == "TerrainLevelIdx") { TerrainRenderable::setCurrentRenderLevelIndex((*static_cast(val))); return true; } if (key == "DepthWrite") { mEnableDepthWrite = (*static_cast(val)); return true; } return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface). setOption(key, val) || TerrainSceneManager::setOption(key, val); } //----------------------------------------------------------------------- bool VisibilityTerrainSceneManager::getOption(const String & key, void *val) { if (key == "NumHierarchyNodes") { * static_cast(val) = (unsigned int)mNumOctreeNodes; return true; } return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface). getOption(key, val) && TerrainSceneManager::getOption(key, val); } //----------------------------------------------------------------------- bool VisibilityTerrainSceneManager::getOptionValues(const String & key, StringVector &refValueList) { return TerrainSceneManager::getOptionValues( key, refValueList); } //----------------------------------------------------------------------- bool VisibilityTerrainSceneManager::getOptionKeys(StringVector & refKeys) { return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface). getOptionKeys(refKeys) || TerrainSceneManager::getOptionKeys(refKeys); } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::setVisibilityManager(GtpVisibility::VisibilityManager *visManager) { mVisibilityManager = visManager; } //----------------------------------------------------------------------- GtpVisibility::VisibilityManager *VisibilityTerrainSceneManager::getVisibilityManager( void ) { return mVisibilityManager; } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::WriteLog() { std::stringstream d; d << "Depth pass: " << StringConverter::toString(mUseDepthPass) << ", " << "Delay transparents: " << StringConverter::toString(mDelayRenderTransparents) << ", " << "Use optimization: " << StringConverter::toString(mHierarchyInterface->GetUseOptimization()) << ", " << "Algorithm type: " << mVisibilityManager->GetCullingManagerType() << ", " << "Hierarchy nodes: " << mNumOctreeNodes << ", " << "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 VisibilityTerrainSceneManager::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 VisibilityTerrainSceneManager::validatePassForRendering(Pass* pass) { // skip all but first pass if we are doing the depth pass if ((mRenderDepthPass || mRenderItemBuffer) && pass->getIndex() > 0) { return false; } return SceneManager::validatePassForRendering(pass); } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::renderQueueGroupObjects(RenderQueueGroup* pGroup) { if (!mRenderItemBuffer) { TerrainSceneManager::renderQueueGroupObjects(pGroup); return; } //--- item buffer // Iterate through priorities RenderQueueGroup::PriorityMapIterator groupIt = pGroup->getIterator(); while (groupIt.hasMoreElements()) { RenderItemBuffer(groupIt.getNext()); } } //----------------------------------------------------------------------- void VisibilityTerrainSceneManager::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(); //<< ", renderable name: " << irend-> LogManager::getSingleton().logMessage(d.str()); //if(ipass->first->getParent()->getParent()->getName() == "Examples/Athene") //<< ", renderable name: " << irend-> RenderSingleObjectForItemBuffer(*irend, ipass->first); //RenderSingleObjectForOcclusionQuery( } } // ----- TRANSPARENT LOOP: must be handled differently // although we don't really care about transparents for the item buffer // TODO: HOW TO HANDLE OCCLUDED OBJECTS ???? 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 VisibilityTerrainSceneManager::RenderSingleObjectForItemBuffer(Renderable *rend, Pass *pass) { static LightList nullLightList; Real col = (Real)rend->getId() / (Real)mCurrentEntityId; mItemBufferPass->setAmbient(ColourValue(0, 1, 1)); //mItemBufferPass->setDiffuse(ColourValue(0, col, 0)); // mItemBufferPass->setSpecular(ColourValue(0, col, 0)); // mItemBufferPass->_load(); // set vertex program of current pass if (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(""); } //LogManager::getSingleton().logMessage("has vertex program"); Pass *usedPass = setPass(mItemBufferPass); //Pass *usedPass = setPass(pass); std::stringstream d; d << "item buffer id: " << rend->getId() << ", col: " << col; LogManager::getSingleton().logMessage(d.str()); // Render a single object, this will set up auto params if required renderSingleObject(rend, usedPass, false, &nullLightList); } //----------------------------------------------------------------------- GtpVisibility::VisibilityManager *VisibilityTerrainSceneManager::GetVisibilityManager() { return mVisibilityManager; } //----------------------------------------------------------------------- Entity* VisibilityTerrainSceneManager::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 ++); } return ent; } } // namespace Ogre