#include "RandomUpdateCullingManager.h" #include #include "CullingLogManager.h" #include //#include #include using namespace std; namespace GtpVisibility { const static int R_CANDIDATES = 1; //----------------------------------------------------------------------- RandomUpdateCullingManager::RandomUpdateCullingManager(): mRandomCandidates(R_CANDIDATES) { } //----------------------------------------------------------------------- RandomUpdateCullingManager::RandomUpdateCullingManager(const unsigned int randomCandidates) { mRandomCandidates = std::max(randomCandidates, (unsigned int)1); } //----------------------------------------------------------------------- void RandomUpdateCullingManager::SetRandomCandidates(const unsigned int randomCandidates) { mRandomCandidates = std::max(randomCandidates, (unsigned int)1); } //----------------------------------------------------------------------- void RandomUpdateCullingManager::RenderScene() { if (0) CullingLogManager::GetSingleton()->LogMessage("ruc"); QueryQueue queryQueue; unsigned int visiblePixels = 0; ///////////// //-- PART 1: process finished occlusion queries while (!mHierarchyInterface->GetQueue()->empty() || !queryQueue.empty()) { bool resultAvailable = false; //-- only wait for result if there are no nodes to process while (!queryQueue.empty() && queryQueue.front().second->GetQueryResult(visiblePixels, mHierarchyInterface->GetQueue()->empty())) { HierarchyNode *node = queryQueue.front().first; queryQueue.pop(); if (visiblePixels > mVisibilityThreshold) { // in case geometry is in interior node: // ensure that we only traverse once if (!mHierarchyInterface->IsNodeVisible(node) && !mHierarchyInterface->IsNodeFullyVisible(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 { // fully visible subtree => render all in one batch if (mHierarchyInterface->IsNodeFullyVisible(node)) { int nodesTested = 0; // use different algorithm for finding random candidates #if 1 HierarchyNodeContainer mynodes; mHierarchyInterface->CollectLeaves(node, mynodes); const int p = mRandomCandidates * RAND_MAX / (int)mynodes.size(); HierarchyNodeContainer::const_iterator nit, nit_end = mynodes.end(); for (nit = mynodes.begin(); nit != nit_end; ++ nit) { HierarchyNode *leaf = *nit; if (rand() > p) continue; bool intersects = false; const bool frustumCulled = !mHierarchyInterface->CheckFrustumVisible(leaf, intersects); // don't test in these cases ... if (frustumCulled || intersects) continue; ++ nodesTested; mHierarchyInterface->SetNodeVisible(leaf, false); // update node's visited flag: this is important as we are not testing // all nodes in the hierarchy in this mode mHierarchyInterface->PullUpLastVisited(leaf, mHierarchyInterface->GetFrameId()); // issue the query mHierarchyInterface->IssueNodeOcclusionQuery(node, mTestGeometryForVisibleLeaves); } //std::stringstream d; d << "rc: " << mRandomCandidates << " tested: " << nodesTested << " of " << (int)mynodes.size(); //CullingLogManager::GetSingleton()->LogMessage(d.str()); #else HierarchyNode *leaf = mHierarchyInterface->GetRandomLeaf(node); bool intersects = false; const bool frustumCulled = !mHierarchyInterface->CheckFrustumVisible(leaf, intersects); if (frustumCulled || intersects) // don't test in these cases ... continue; ++ nodesTested; mHierarchyInterface->SetNodeVisible(leaf, false); // update node's visited flag: this is important as we are not testing // all nodes in the hierarchy in this mode mHierarchyInterface->PullUpLastVisited(leaf, mHierarchyInterface->GetFrameId()); // issue the query mHierarchyInterface->IssueNodeOcclusionQuery(leaf, mTestGeometryForVisibleLeaves); #endif mHierarchyInterface->RenderNodeRecursive(node); // bail out here, recursion has finished continue; } // identify previously visible nodes const 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 = false; //wasVisible && 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 const bool issueQuery = !wasVisible || mHierarchyInterface->HasGeometry(node); // reset node's visibility classification // set visible if geometry in node => we only traverse the node 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; const bool testGeometry = wasVisible && mHierarchyInterface->IsLeaf(node) && mTestGeometryForVisibleLeaves; queryQueue.push(QueryPair(node, mHierarchyInterface-> IssueNodeOcclusionQuery(node, testGeometry))); } // always traverse a node if it was visible if (wasVisible) { mHierarchyInterface->TraverseNode(node); } } } } // update the fully visible classifications mHierarchyInterface->DetermineFullVisibility(mHierarchyInterface->GetHierarchyRoot()); } //----------------------------------------------------------------------- inline void RandomUpdateCullingManager::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); } //----------------------------------------------------------------------- void RandomUpdateCullingManager::SetTestGeometryForVisibleLeaves(const bool testGeometry) { mTestGeometryForVisibleLeaves = testGeometry; } //----------------------------------------------------------------------- bool RandomUpdateCullingManager::GetTestGeometryForVisibleLeaves() { return mTestGeometryForVisibleLeaves; } } // namespace GtpVisibility