#include "OgreOcclusionQueriesQueryManager.h" #include #include #include #include namespace Ogre { //----------------------------------------------------------------------- bool nodeinfo_eq(const GtpVisibility::NodeInfo &a, const GtpVisibility::NodeInfo &b) { return a.GetSource() == b.GetSource(); } bool nodeinfo_lt(const GtpVisibility::NodeInfo &a, const GtpVisibility::NodeInfo &b) { return a.GetSource() < b.GetSource(); } bool meshinfo_eq(const GtpVisibility::MeshInfo &a, const GtpVisibility::MeshInfo &b) { return a.GetSource() == b.GetSource(); } bool meshinfo_lt(const GtpVisibility::MeshInfo &a, const GtpVisibility::MeshInfo &b) { return a.GetSource() < b.GetSource(); } bool patchinfo_eq(const GtpVisibility::PatchInfo &a, const GtpVisibility::PatchInfo &b) { return a.GetSource() == b.GetSource(); } bool patchinfo_lt(const GtpVisibility::PatchInfo &a, const GtpVisibility::PatchInfo &b) { return a.GetSource() < b.GetSource(); } //----------------------------------------------------------------------- OcclusionQueriesQueryManager::OcclusionQueriesQueryManager( PlatformHierarchyInterface *hierarchyInterface, Viewport *vp, int queryModes, int itemBufferMode): PlatformQueryManager(hierarchyInterface, vp, queryModes), mItemBufferMode(itemBufferMode) { } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::ComputeCameraVisibility(const Camera &camera, GtpVisibility::NodeInfoContainer *visibleNodes, GtpVisibility::MeshInfoContainer *visibleGeometry, GtpVisibility::PatchInfoContainer *visiblePatches, bool relativeVisibility) { // we need access to the scene manager and the rendersystem PlatformHierarchyInterface *pfHierarchyInterface = dynamic_cast(mHierarchyInterface); // disable overlays, reset them later bool overlayEnabled = mViewport->getOverlaysEnabled(); //-- render scene with item buffer (i.e., objects with their id as color codes) //mItemBufferMode = 0; if ((mItemBufferMode && mQueryModes) != 0) { int savedQueryModes = mQueryModes; mQueryModes = mItemBufferMode; PlatformQueryManager::ComputeCameraVisibility(camera, visibleNodes, visibleGeometry, visiblePatches, relativeVisibility); // 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 pfHierarchyInterface->GetSceneManager()->_renderScene(pCam, mViewport, false); } /* 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::HierarchyNodeList *visNodes = mHierarchyInterface->GetVisibleNodes(); GtpVisibility::HierarchyNodeList::iterator visNodesIt, visNodesIt_end = visNodes->end(); GtpVisibility::HierarchyNodeList nodeList; if (mQueryModes & NODE_VISIBILITY) { for (visNodesIt = visNodes->begin(); visNodesIt != visNodesIt_end; ++visNodesIt) { nodeList.push_back((*visNodesIt)); } } GtpVisibility::HierarchyNodeList::iterator nodeIt, nodeIt_end = nodeList.end(); // vector for storing entities of meshes GtpVisibility::GeometryList 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 GtpVisibility::GeometryList::iterator geometryIt, geometryIt_end = geometryList.end(); // vector for storing subentities of meshes GtpVisibility::PatchList 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); } } GtpVisibility::PatchList::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("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 queryList[i].push_back(mHierarchyInterface->IssueNodeOcclusionQuery(*nodeIt, false)); } //-- queries for geometry: if item buffer, capture only projected visibility if ((mItemBufferMode != GEOMETRY_VISIBILITY) || (i == 1)) { for (geometryIt = geometryList.begin(); geometryIt != geometryIt_end; ++geometryIt) { queryList[i].push_back(pfHierarchyInterface->IssueMeshOcclusionQuery(*geometryIt)); } } //-- queries for patches: if item buffer, capture only projected visibility if ((mItemBufferMode != PATCH_VISIBILITY) || (i == 1)) { for (patchIt = patchList.begin(); patchIt != patchIt_end; ++patchIt) { 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 options 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, GtpVisibility::NodeInfoContainer *visibleNodes, GtpVisibility::MeshInfoContainer *visibleGeometry, GtpVisibility::PatchInfoContainer *visiblePatches, bool relativeVisibility) { PlatformQueryManager::ComputeFromPointVisibility(point, visibleNodes, visibleGeometry, visiblePatches, relativeVisibility); // 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); } } //------j----------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectNodeVisibility( GtpVisibility::QueryList::iterator &visQueryIt, GtpVisibility::QueryList::iterator &projQueryIt, GtpVisibility::HierarchyNodeList *nodeList, GtpVisibility::NodeInfoContainer *visibleNodes, bool relativeVisibility) { GtpVisibility::HierarchyNodeList::iterator nodeIt; //-- queries for nodes for (nodeIt = nodeList->begin(); nodeIt != nodeList->end(); ++nodeIt) { 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(GtpVisibility::NodeInfo(*nodeIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectRelativeGeometryVisibilityForItemBuffer( GtpVisibility::QueryList::iterator &projQueryIt, GtpVisibility::GeometryList *geometryList, GtpVisibility::MeshInfoContainer *visibleGeometry) { GtpVisibility::GeometryList::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, GtpVisibility::PatchList *patchList, GtpVisibility::PatchInfoContainer *visiblePatches) { GtpVisibility::PatchList::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, GtpVisibility::GeometryList *geometryList, GtpVisibility::MeshInfoContainer *visibleGeometry, bool relativeVisibility) { GtpVisibility::GeometryList::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 => // geometry maybe occluded if (visiblePixels > 0) { visibleGeometry->push_back(GtpVisibility::MeshInfo(*geometryIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::CollectPatchVisibility( GtpVisibility::QueryList::iterator &visQueryIt, GtpVisibility::QueryList::iterator &projQueryIt, GtpVisibility::PatchList *patchList, GtpVisibility::PatchInfoContainer *visiblePatches, bool relativeVisibility) { GtpVisibility::PatchList::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(GtpVisibility::PatchInfo(*patchIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::RemoveDuplicateNodes( GtpVisibility::NodeInfoContainer *visibleNodes) { sort(visibleNodes->begin(), visibleNodes->end(), nodeinfo_lt); GtpVisibility::NodeInfoContainer::iterator visibleNodesIt, visibleNodesIt_end = visibleNodes->end(); GtpVisibility::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(), nodeinfo_eq), visibleNodes->end()); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::RemoveDuplicateGeometry( GtpVisibility::MeshInfoContainer *visibleGeometry) { sort(visibleGeometry->begin(), visibleGeometry->end(), meshinfo_lt); GtpVisibility::MeshInfoContainer::iterator visibleGeomIt, visibleGeomIt_end = visibleGeometry->end(); GtpVisibility::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(), meshinfo_eq), visibleGeometry->end()); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::RemoveDuplicatePatches( GtpVisibility::PatchInfoContainer *visiblePatches) { sort(visiblePatches->begin(), visiblePatches->end(), patchinfo_lt); GtpVisibility::PatchInfoContainer::iterator visiblePatchIt, visiblePatchIt_end = visiblePatches->end(); GtpVisibility::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(), patchinfo_eq), visiblePatches->end()); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::GetNodePatchList(GtpVisibility::HierarchyNode *node, GtpVisibility::PatchList *patchList) { GtpVisibility::GeometryList geomList; mHierarchyInterface->GetNodeGeometryList(node, &geomList, false); // geometry list iterator GtpVisibility::GeometryList::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