#include #include #include #include #include "OgreOcclusionQueriesQueryManager.h" //#include "OgrePlatformHierarchyInterface.h" #include "OgreOcclusionCullingSceneManager.h" #include "VisibilityEnvironment.h" namespace Ogre { //----------------------------------------------------------------------- /*OcclusionQueriesQueryManager::OcclusionQueriesQueryManager( PlatformHierarchyInterface *hierarchyInterface, Viewport *vp, int queryModes, int itemBufferMode) :PlatformQueryManager(hierarchyInterface, vp, queryModes), mItemBufferMode(itemBufferMode) { }*/ //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::ComputeCameraVisibility( const Camera &camera, NodeInfoContainer *visibleNodes, MeshInfoContainer *visibleGeometry, PatchInfoContainer *visiblePatches, const bool relativeVisibility, const bool approximateVisibility) { // we need access to the scene manager and the rendersystem PlatformHierarchyInterface *pfHierarchyInterface = static_cast(mHierarchyInterface); // disable overlays, reset them later bool overlayEnabled = mViewport->getOverlaysEnabled(); //mItemBufferMode = 0; if (0 && (mItemBufferMode && mQueryModes) != 0) { /////////// //-- render scene with item buffer (ids are used as color codes) int savedQueryModes = mQueryModes; mQueryModes = mItemBufferMode; PlatformQueryManager::ComputeCameraVisibility(camera, visibleNodes, visibleGeometry, visiblePatches, relativeVisibility, approximateVisibility); // overlays cause false visibility mViewport->setOverlaysEnabled(false); mQueryModes = savedQueryModes; } else { // const_cast allowed because camera is not changed in renderScene Camera *pCam = const_cast(&camera); mViewport->setOverlaysEnabled(false); //////////////////////// //-- Render scene to get conservative visibility and fill depth buffer OcclusionCullingSceneManager *occlusionSceneMgr = static_cast(pfHierarchyInterface->GetSceneManager()); // no visibility manager available => no visibility scene manager, return GtpVisibility::VisibilityManager *visManager = NULL; if (!occlusionSceneMgr->getOption("VisibilityManager", &visManager)) { Ogre::LogManager::getSingleton().logMessage("no vismanager found"); return; } // use stop and wait culling for from view point queries because probably // no temporal coherence GtpVisibility::VisibilityEnvironment::CullingManagerType occlusionType = visManager->GetCullingManagerType(); visManager->SetCullingManager(GtpVisibility::VisibilityEnvironment::STOP_AND_WAIT_CULLING); if (1) occlusionSceneMgr->RenderDepthForQuery(pCam, mViewport); else pfHierarchyInterface->GetSceneManager()->_renderScene(pCam, mViewport, false); visManager->SetCullingManager(occlusionType); } /** Two query lists for projected pixels and for visibile pixels: We test queries after a rendering pass to get exact visibility with regard to the current camera. We issue all queries at once to avoid starvation & stalls. */ GtpVisibility::QueryList queryList[2]; // rendered visibile hierarchy nodes from previous rendering GtpVisibility::NodeVector *visNodes = mHierarchyInterface->GetVisibleNodes(); GtpVisibility::NodeVector::iterator visNodesIt, visNodesIt_end = visNodes->end(); GtpVisibility::NodeVector nodeList; if (mQueryModes & NODE_VISIBILITY) { for (visNodesIt = visNodes->begin(); visNodesIt != visNodesIt_end; ++visNodesIt) { nodeList.push_back((*visNodesIt)); } } GtpVisibility::NodeVector::iterator nodeIt, nodeIt_end = nodeList.end(); // vector for storing entities of meshes GeometryVector geometryList; // store geometry of the hierarchy nodes in a geometry list if (mQueryModes & GEOMETRY_VISIBILITY) { for (visNodesIt = visNodes->begin(); visNodesIt != visNodesIt_end; ++ visNodesIt) { mHierarchyInterface->GetNodeGeometryList(*visNodesIt, &geometryList, false); } } // geometry list iterator GeometryVector::iterator geometryIt, geometryIt_end = geometryList.end(); // vector for storing subentities of meshes PatchVector patchList; // store patchges of the geometries in a patch list if (mQueryModes & PATCH_VISIBILITY) { for (visNodesIt = visNodes->begin(); visNodesIt != visNodesIt_end; ++visNodesIt) { GetNodePatchList(*visNodesIt, &patchList); } } PatchVector::iterator patchIt, patchIt_end = patchList.end(); // to obtain the correct number of projected pixels, depth write must be disabled bool enableDepthWrite = false; // this option must be provided by the scene manager pfHierarchyInterface->GetSceneManager()->setOption("DepthWrite", &enableDepthWrite); /* relative visiblity: 1) get visible pixels count of objects 2) clear frame buffer 3) get projected visible pixels count: test all objects again without depth write (set as option in scene manager) 4) calculate ratio between visible vs. projected pixels */ // for relative visibility we need 2 rendering passes int n = relativeVisibility ? 2 : 1; if (mItemBufferMode > 0) LogManager::getSingleton().logMessage("using item buffer"); for (int i = 0; i < n; ++ i) { //-- queries for hierarchy nodes for (nodeIt = nodeList.begin(); nodeIt != nodeIt_end; ++ nodeIt) { // TODO: DELETE QUERIES FROM PREVIOUS RENDER bool intersects = false; pfHierarchyInterface->CheckFrustumVisible(*nodeIt, intersects); // always push back if only checking approximate visibility or intersects if (approximateVisibility || intersects) { // no more information available const int visPixels = 1; const int projPixels = 1; visibleNodes->push_back(NodeInfo(*nodeIt, visPixels, projPixels)); queryList[i].push_back(NULL); } else // issue occlusion query { queryList[i].push_back(mHierarchyInterface->IssueNodeOcclusionQuery(*nodeIt, false)); } } /////////////// //-- queries for geometry // note: for item buffer we can capture only projected visibility if ((mItemBufferMode != GEOMETRY_VISIBILITY) || (i == 1)) { for (geometryIt = geometryList.begin(); geometryIt != geometryIt_end; ++ geometryIt) { if (approximateVisibility) { // no more information available const int visPixels = 1; const int projPixels = 1; visibleGeometry->push_back(MeshInfo(*geometryIt, visPixels, projPixels)); } else { queryList[i].push_back(pfHierarchyInterface->IssueMeshOcclusionQuery(*geometryIt)); } } } /////////////// //-- queries for patches if ((mItemBufferMode != PATCH_VISIBILITY) || (i == 1)) { for (patchIt = patchList.begin(); patchIt != patchIt_end; ++patchIt) { if (approximateVisibility) { // no more information available const int visPixels = 1; const int projPixels = 1; visiblePatches->push_back(PatchInfo(*patchIt, visPixels, projPixels)); } else { queryList[i].push_back(pfHierarchyInterface->IssuePatchOcclusionQuery(*patchIt)); } } } pfHierarchyInterface->GetRenderSystem()->clearFrameBuffer(FBT_DEPTH); } /////////////// //-- collect results GtpVisibility::QueryList::iterator visQueryIt = queryList[0].begin(); GtpVisibility::QueryList::iterator projQueryIt = queryList[1].begin(); // collect occlusion queries for hierarchy nodes CollectNodeVisibility(visQueryIt, projQueryIt, &nodeList, visibleNodes, relativeVisibility); // collect occlusion queries for geometry if ((mItemBufferMode == GEOMETRY_VISIBILITY) && relativeVisibility) { // if visibility was established using the item buffer, // the array is organized different (e.g., ordered by id, all possible objects) CollectRelativeGeometryVisibilityForItemBuffer(projQueryIt, &geometryList, visibleGeometry); } else if (mItemBufferMode != GEOMETRY_VISIBILITY) { CollectGeometryVisibility(visQueryIt, projQueryIt, &geometryList, visibleGeometry, relativeVisibility); } // collect occlusion queries for patches if ((mItemBufferMode == PATCH_VISIBILITY) && relativeVisibility) { CollectRelativePatchVisibilityForItemBuffer(projQueryIt, &patchList, visiblePatches); } else if (mItemBufferMode != PATCH_VISIBILITY) { CollectPatchVisibility(visQueryIt, projQueryIt, &patchList, visiblePatches, relativeVisibility); } //////////// //-- reset state enableDepthWrite = true; // this option must be provided by the scene manager pfHierarchyInterface->GetSceneManager()->setOption("DepthWrite", &enableDepthWrite); // reset old overlay status mViewport->setOverlaysEnabled(overlayEnabled); mWasInitialised = false; } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::ComputeFromPointVisibility( const Vector3 &point, NodeInfoContainer *visibleNodes, MeshInfoContainer *visibleGeometry, PatchInfoContainer *visiblePatches, const bool relativeVisibility, const bool approximateVisibility) { PlatformQueryManager::ComputeFromPointVisibility(point, visibleNodes, visibleGeometry, visiblePatches, relativeVisibility, approximateVisibility); // adds up their visibility and removes duplicates // (duplicates occur if an object is on the edge of the viewport) RemoveDuplicateNodes(visibleNodes); if (mItemBufferMode != GEOMETRY_VISIBILITY) { RemoveDuplicateGeometry(visibleGeometry); } if (mItemBufferMode != PATCH_VISIBILITY) { RemoveDuplicatePatches(visiblePatches); } } //------------------------------------------------------------------------ void OcclusionQueriesQueryManager::CollectNodeVisibility( GtpVisibility::QueryList::iterator &visQueryIt, GtpVisibility::QueryList::iterator &projQueryIt, GtpVisibility::NodeVector *nodeList, NodeInfoContainer *visibleNodes, bool relativeVisibility) { GtpVisibility::NodeVector::iterator nodeIt; //-- queries for nodes for (nodeIt = nodeList->begin(); nodeIt != nodeList->end(); ++ nodeIt) { if (!(*visQueryIt)) { ++ visQueryIt; if (relativeVisibility) ++ projQueryIt; continue; } unsigned int visiblePixels = 0; (*visQueryIt)->GetQueryResult(visiblePixels, true); unsigned int projectedPixels = 0; if (relativeVisibility) { (*projQueryIt)->GetQueryResult(projectedPixels, true); ++ projQueryIt; } ++ visQueryIt; // node with visibilty 0 in queue (e.g., if node is intersected by near plane) if (visiblePixels > 0) { visibleNodes->push_back(NodeInfo(*nodeIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectRelativeGeometryVisibilityForItemBuffer( GtpVisibility::QueryList::iterator &projQueryIt, GeometryVector *geometryList, MeshInfoContainer *visibleGeometry) { GeometryVector::iterator geometryIt; //-- queries for geometry for (geometryIt = geometryList->begin(); geometryIt != geometryList->end(); ++ geometryIt) { unsigned int projectedPixels = 0; (*projQueryIt)->GetQueryResult(projectedPixels, true); ++projQueryIt; int id = (*geometryIt)->getSubEntity(0)->getId(); if ((id > 0) && (id < (int)visibleGeometry->size())) { (*visibleGeometry)[id].AddVisibility(0, projectedPixels); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectRelativePatchVisibilityForItemBuffer( GtpVisibility::QueryList::iterator &projQueryIt, PatchVector *patchList, PatchInfoContainer *visiblePatches) { PatchVector::iterator patchIt; //-- queries for geometry for (patchIt = patchList->begin(); patchIt != patchList->end(); ++ patchIt) { unsigned int projectedPixels = 0; (*projQueryIt)->GetQueryResult(projectedPixels, true); ++projQueryIt; int id = (*patchIt)->getId(); if ((id > 0) && (id < (int)visiblePatches->size())) { (*visiblePatches)[id].AddVisibility(0, projectedPixels); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectGeometryVisibility( GtpVisibility::QueryList::iterator &visQueryIt, GtpVisibility::QueryList::iterator &projQueryIt, GeometryVector *geometryList, MeshInfoContainer *visibleGeometry, bool relativeVisibility) { GeometryVector::iterator geometryIt; //-- queries for geometry for (geometryIt = geometryList->begin(); geometryIt != geometryList->end(); ++ geometryIt) { unsigned int visiblePixels = 0; (*visQueryIt)->GetQueryResult(visiblePixels, true); unsigned int projectedPixels = 0; if (relativeVisibility) { (*projQueryIt)->GetQueryResult(projectedPixels, true); ++ projQueryIt; } ++ visQueryIt; // WARNING: approximate depth ordering during rendering => // visibility approximate if (visiblePixels > 0) { visibleGeometry->push_back(MeshInfo(*geometryIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectPatchVisibility( GtpVisibility::QueryList::iterator &visQueryIt, GtpVisibility::QueryList::iterator &projQueryIt, PatchVector *patchList, PatchInfoContainer *visiblePatches, bool relativeVisibility) { PatchVector::iterator patchIt; //-- queries for patch for (patchIt = patchList->begin(); patchIt != patchList->end(); ++ patchIt) { unsigned int visiblePixels = 0; (*visQueryIt)->GetQueryResult(visiblePixels, true); unsigned int projectedPixels = 0; if (relativeVisibility) { (*projQueryIt)->GetQueryResult(projectedPixels, true); ++ projQueryIt; } ++ visQueryIt; // WARNING: approximate depth ordering during rendering => // patch maybe occluded if (visiblePixels > 0) { visiblePatches->push_back( PatchInfo(*patchIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::RemoveDuplicateNodes( NodeInfoContainer *visibleNodes) { sort(visibleNodes->begin(), visibleNodes->end()); NodeInfoContainer::iterator visibleNodesIt, visibleNodesIt_end = visibleNodes->end(); NodeInfo *nodeInfo = NULL; for (visibleNodesIt = visibleNodes->begin(); visibleNodesIt != visibleNodesIt_end; ++visibleNodesIt) { if (!nodeInfo || (nodeInfo->GetSource() != (*visibleNodesIt).GetSource())) { nodeInfo = &(*visibleNodesIt); } else // add visibility { nodeInfo->AddVisibility(*visibleNodesIt); } } // physically delete duplicates visibleNodes->erase(std::unique(visibleNodes->begin(), visibleNodes->end()), visibleNodes->end()); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::RemoveDuplicateGeometry( MeshInfoContainer *visibleGeometry) { sort(visibleGeometry->begin(), visibleGeometry->end()); MeshInfoContainer::iterator visibleGeomIt, visibleGeomIt_end = visibleGeometry->end(); MeshInfo *geomInfo = NULL; for (visibleGeomIt = visibleGeometry->begin(); visibleGeomIt != visibleGeomIt_end; ++visibleGeomIt) { if (!geomInfo || (geomInfo->GetSource() != (*visibleGeomIt).GetSource())) { geomInfo = &(*visibleGeomIt); } else // info points to same mesh, just add visibility { geomInfo->AddVisibility(*visibleGeomIt); } } // physically delete duplicates visibleGeometry->erase(std::unique(visibleGeometry->begin(), visibleGeometry->end()), visibleGeometry->end()); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::RemoveDuplicatePatches( PatchInfoContainer *visiblePatches) { sort(visiblePatches->begin(), visiblePatches->end()); PatchInfoContainer::iterator visiblePatchIt, visiblePatchIt_end = visiblePatches->end(); PatchInfo *patchInfo = NULL; for (visiblePatchIt = visiblePatches->begin(); visiblePatchIt != visiblePatchIt_end; ++visiblePatchIt) { if (!patchInfo || (patchInfo->GetSource() != (*visiblePatchIt).GetSource())) { patchInfo = &(*visiblePatchIt); } else // info points to same mesh, just add visibility { patchInfo->AddVisibility(*visiblePatchIt); } } // physically delete duplicates visiblePatches->erase(std::unique(visiblePatches->begin(), visiblePatches->end()), visiblePatches->end()); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::GetNodePatchList(GtpVisibility::HierarchyNode *node, PatchVector *patchList) { GeometryVector geomList; mHierarchyInterface->GetNodeGeometryList(node, &geomList, false); // geometry list iterator GeometryVector::iterator geomIt, geomIt_end = geomList.end(); for (geomIt = geomList.begin(); geomIt != geomIt_end; ++geomIt) { for (int i = 0; i < (int)(*geomIt)->getNumSubEntities(); ++i) { patchList->push_back((*geomIt)->getSubEntity(i)); } } } } // namespace Ogre