#include "CoherentHierarchicalCullingManager.h" #include "CullingLogManager.h" #include #include namespace GtpVisibility { static int batchSize = 5; //----------------------------------------------------------------------- CoherentHierarchicalCullingManager::CoherentHierarchicalCullingManager(): mAssumedVisibility(0) { } //----------------------------------------------------------------------- CoherentHierarchicalCullingManager::CoherentHierarchicalCullingManager( const unsigned int assumedVisibility): mAssumedVisibility(assumedVisibility) { } //----------------------------------------------------------------------- void CoherentHierarchicalCullingManager::AssignAssumedVisibility(GtpVisibility::HierarchyNode *node) { if (!mHierarchyInterface->IsNodeVisible(node)) // previously invisible nodes: give random offset just for the first test after // becoming visible to avoid that all nodes are tested in the same frame mHierarchyInterface->SetNodeAssumedVisible(node, rand() * mAssumedVisibility / RAND_MAX); else mHierarchyInterface->SetNodeAssumedVisible(node, mAssumedVisibility); } //----------------------------------------------------------------------- void CoherentHierarchicalCullingManager::RenderScene() { if (0) CullingLogManager::GetSingleton()->LogMessage("chc"); QueryQueue queryQueue; unsigned int visiblePixels = 0; ///////////// //-- PART 1: process finished occlusion queries while (!mHierarchyInterface->GetQueue()->empty() || !queryQueue.empty()) { ////////// //-- only wait for result if there are no nodes to process while (!queryQueue.empty() && (NodeInvalid(queryQueue.front().first) || queryQueue.front().second->GetQueryResult( visiblePixels, mHierarchyInterface->GetQueue()->empty()))) { HierarchyNode *node = queryQueue.front().first; queryQueue.pop(); // "invalid nodes" happen for hierarchies that have geometry // not neccessarily in the leaves: // parent was tested invisible => remove children from queue if (1 && NodeInvalid(node)) continue; // tested visible if (visiblePixels > mVisibilityThreshold) { // assing the #frames the node is assumed to stay visible AssignAssumedVisibility(node); // for previously visible interior node which contains geometry: // ensure that we did not already traverse this node // (which means that the visibility flag is set) if (!mHierarchyInterface->IsNodeVisible(node)) mHierarchyInterface->TraverseNode(node); mHierarchyInterface->PullUpVisibility(node); } else { mHierarchyInterface->SetNodeVisible(node, false); ++ mNumQueryCulledNodes; if (mVisualizeCulledNodes) mHierarchyInterface->VisualizeCulledNode(node, QUERY_CULLED); } // update node's visited flag mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId()); } //////////////// //-- PART 2: hierarchical traversal if (!mHierarchyInterface->GetQueue()->empty()) { HierarchyNode *node = mHierarchyInterface->GetQueue()->top(); mHierarchyInterface->GetQueue()->pop(); // parent was tested invisible => remove children from queue if (1 && NodeInvalid(node)) continue; 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 const bool skipQuery = wasVisible && DecideVisible(node) && mHierarchyInterface->HasGeometry(node); 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); // set node's visibility classification // we identify previously visible / invisible nodes in the query queue mHierarchyInterface->SetNodeVisible(node, wasVisible && issueQuery); if (issueQuery) { ++ mNumQueriesIssued; const bool testGeometry = wasVisible && mHierarchyInterface->IsLeaf(node) && mTestGeometryForVisibleLeaves; queryQueue.push(QueryPair(node, mHierarchyInterface-> IssueNodeOcclusionQuery(node, testGeometry))); } else { // skip testing previously visible nodes without geometry // just update node's visited flag mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId()); } // always traverse a node if it was visible if (wasVisible) { mHierarchyInterface->TraverseNode(node); } } } } } //----------------------------------------------------------------------- void CoherentHierarchicalCullingManager::SetAssumedVisibility(const unsigned int assumedVisibility) { mAssumedVisibility = assumedVisibility; } //----------------------------------------------------------------------- inline bool CoherentHierarchicalCullingManager::DecideVisible(HierarchyNode *node) const { mHierarchyInterface->DecNodeAssumedVisible(node); //std::stringstream d; d << "node visible: " << mHierarchyInterface->GetNodeAssumedVisible(node); //CullingLogManager::GetSingleton()->LogMessage(d.str()); return mHierarchyInterface->GetNodeAssumedVisible(node) > 0; } //----------------------------------------------------------------------- inline void CoherentHierarchicalCullingManager::SkipQuery(HierarchyNode *node) const { //-- set node to be visible in this frame, then traverse it mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId()); mHierarchyInterface->PullUpVisibility(node); mHierarchyInterface->TraverseNode(node); } //----------------------------------------------------------------------- bool CoherentHierarchicalCullingManager::NodeInvalid(HierarchyNode *node) const { // parent was tested invisible in this frame HierarchyNode *parent = mHierarchyInterface->GetParent(node); return parent && (mHierarchyInterface->LastVisited(node) == mHierarchyInterface->GetFrameId()) && !mHierarchyInterface->IsNodeVisible(parent); } //----------------------------------------------------------------------- void CoherentHierarchicalCullingManager::SetTestGeometryForVisibleLeaves(const bool testGeometry) { mTestGeometryForVisibleLeaves = testGeometry; } //----------------------------------------------------------------------- bool CoherentHierarchicalCullingManager::GetTestGeometryForVisibleLeaves() { return mTestGeometryForVisibleLeaves; } }