#include "BatchedQueriesCullingManager.h" #include namespace GtpVisibility { //----------------------------------------------------------------------- BatchedQueriesCullingManager::BatchedQueriesCullingManager(): mMaxPending(5) { } //----------------------------------------------------------------------- BatchedQueriesCullingManager::BatchedQueriesCullingManager(const unsigned int assumedVisibility): CoherentHierarchicalCullingManager(assumedVisibility), mMaxPending(5) { } //----------------------------------------------------------------------- void BatchedQueriesCullingManager::RenderScene() { QueryQueue queryQueue; unsigned int visiblePixels = 0; //Ogre::LogManager::getSingleton().logMessage("Batched Culling"); PendingQueue pendingQueue; //-- PART 1: process finished occlusion queries while (!mHierarchyInterface->GetQueue()->empty() || !queryQueue.empty() ||!pendingQueue.empty()) { while (!queryQueue.empty() && queryQueue.front().second->GetQueryResult(visiblePixels, mHierarchyInterface->GetQueue()->empty())) { HierarchyNode *node = queryQueue.front().first; queryQueue.pop(); if (visiblePixels > mVisibilityThreshold) { // ensure that we only traverse once if geometry in node if (!mHierarchyInterface->IsNodeVisible(node)) mHierarchyInterface->TraverseNode(node); mHierarchyInterface->PullUpVisibility(node); } else { mHierarchyInterface->SetNodeVisible(node, false); ++ mNumQueryCulledNodes; if (mVisualizeCulledNodes) { mHierarchyInterface->VisualizeCulledNode(node, QUERY_CULLED); } } } //-- PART 2: hierarchical traversal if (!mHierarchyInterface->GetQueue()->empty()) { HierarchyNode *node = mHierarchyInterface->GetQueue()->top(); mHierarchyInterface->GetQueue()->pop(); bool intersects = false; if (!mHierarchyInterface->CheckFrustumVisible(node, intersects)) { ++ mNumFrustumCulledNodes; if (mVisualizeCulledNodes) { mHierarchyInterface->VisualizeCulledNode(node, FRUSTUM_CULLED); } } // -- if node intersects near plane, skip query because wrong results possible else if (intersects) { SkipQuery(node); } else { // identify previously visible nodes bool wasVisible = mHierarchyInterface->IsNodeVisible(node) && (mHierarchyInterface->LastVisited(node) == mHierarchyInterface->GetFrameId() - 1); // if we assume node to be visible in this frame => skip query bool skipQuery = wasVisible && (mAssumedVisibility > 0) && DecideVisible(node) && mHierarchyInterface->HasGeometry(node); //if (mHierarchyInterface->LastVisited(node) >= mHierarchyInterface->GetFrameId()) // Ogre::LogManager::getSingleton().logMessage("error"); if (skipQuery) { SkipQuery(node); continue; } // identify nodes that we cannot skip queries for // geometry not only in leaves => test for renderable geometry bool issueQuery = !wasVisible || mHierarchyInterface->HasGeometry(node); // reset node's visibility classification // set visibe if geometry in node so we only traverse once mHierarchyInterface->SetNodeVisible(node, wasVisible && issueQuery); // update node's visited flag mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId()); // skip testing previously visible nodes without geometry if (issueQuery) { ++ mNumQueriesIssued; // add to the pending queue instead of immediate query if ((int)pendingQueue.size() < mMaxPending) pendingQueue.push(PendingQuery(node, wasVisible)); else { IssueMultipleQueries(pendingQueue, queryQueue); } } // always traverse a node if it was visible if (wasVisible) { mHierarchyInterface->TraverseNode(node); } } } // issue rest of queries IssueMultipleQueries(pendingQueue, queryQueue); } } void BatchedQueriesCullingManager::IssueMultipleQueries(PendingQueue &pendingQueue, QueryQueue &queryQueue) { while (!pendingQueue.empty()) { HierarchyNode *node = pendingQueue.front().first; const bool wasVisible = pendingQueue.front().second; pendingQueue.pop(); queryQueue.push(QueryPair(node, mHierarchyInterface-> IssueNodeOcclusionQuery(node, wasVisible))); } } void BatchedQueriesCullingManager::SetMaxPending(int maxPending) { mMaxPending = maxPending; } } // namespace GtpVisibility