//! ---|> Evaluator void OccOverheadEvaluator::measure(FrameContext & context,Node & node,const Geometry::Rect & /*r*/) { //float currentRenderingTime=0; //int numTests=0; //int numVBO=0; int numPoly=0; Util::Color4f clearColor(0.5f, 0.5f, 0.9f, 1.0f); { // 1. normal render pass // rc.clearScreen(0.5,0.5,0.9); // context.getRenderingContext().finish(); // node.display(rc,renderingFlags); context.getRenderingContext().clearScreen(clearColor); node.display(context,renderingFlags|USE_WORLD_MATRIX); context.getRenderingContext().clearScreen(clearColor); context.getRenderingContext().finish(); context.getStatistics().beginFrame(); node.display(context,renderingFlags|USE_WORLD_MATRIX); context.getRenderingContext().finish(); context.getStatistics().endFrame(); numPoly=static_cast<int>(context.getStatistics().getValueAsDouble(context.getStatistics().getTrianglesCounter())); } // 2. test all group nodes if their bb is visible and collect them std::deque<GroupNode *> visibleGroupNodes; { // collect geometry nodes in frustum const auto groupNodesInVFList = collectNodesInFrustum<GroupNode>(&node,context.getCamera()->getFrustum()); // setup occlusion queries int numQueries=groupNodesInVFList.size(); if (numQueries==0) { values->push_back(nullptr); // TODO!!! return; // TODO?? } auto queries = new Rendering::OcclusionQuery[numQueries]; // test bounding boxes context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, true, Rendering::Comparison::LEQUAL)); int i=0; // start queries Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext()); for(const auto & groupNode : groupNodesInVFList) { queries[i].begin(); // queries[i].fastBoxTest((*it)->getWorldBB()); Rendering::drawAbsBox(context.getRenderingContext(), groupNode->getWorldBB() ); queries[i].end(); ++i; } Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext()); i=0; // get results for(const auto & groupNode : groupNodesInVFList) { Geometry::Box extendedBox=groupNode->getWorldBB(); extendedBox.resizeAbs(context.getCamera()->getNearPlane()); if (queries[i].getResult() > 0 || extendedBox.contains(context.getCamera()->getWorldOrigin()) ) { visibleGroupNodes.push_back(groupNode); } ++i; } context.getRenderingContext().popDepthBuffer(); delete [] queries; } std::deque<GeometryNode *> geoNodesInVisibleGroupNodes; // 3. collect all direct geometry-node children { struct GeoChildrenCollector:public NodeVisitor { GeoChildrenCollector(std::deque<GeometryNode*> & _geoNodes,FrameContext & _context): geoNodes(_geoNodes),firstNode(true),frameContext(_context) {} virtual ~GeoChildrenCollector() {} std::deque<GeometryNode*> & geoNodes; bool firstNode; FrameContext & frameContext; // ---|> NodeVisitor NodeVisitor::status enter(Node * _node) override { // if this is the first call, continue... if(firstNode) { firstNode=false; return CONTINUE_TRAVERSAL; } // else collect the geometry children and break the traversal. GeometryNode * gn=dynamic_cast<GeometryNode *>(_node); if(gn){ if(frameContext.getCamera()->testBoxFrustumIntersection( _node->getWorldBB()) != Geometry::Frustum::intersection_t::OUTSIDE) geoNodes.push_back(gn); } return BREAK_TRAVERSAL; } }; for (auto & visibleGroupNode : visibleGroupNodes) { GeoChildrenCollector vis(geoNodesInVisibleGroupNodes,context); (visibleGroupNode)->traverse(vis); } } // 4. clear screen and measure time drawing children float perfectRenderingTime=0; { context.getRenderingContext().clearScreen(clearColor); context.getRenderingContext().finish(); Util::Timer timer; timer.reset(); for (auto & geoNodesInVisibleGroupNode : geoNodesInVisibleGroupNodes) { context.displayNode((geoNodesInVisibleGroupNode),renderingFlags|USE_WORLD_MATRIX); } context.getRenderingContext().finish(); timer.stop(); perfectRenderingTime=timer.getMilliseconds(); } // // Test-costs: // float result=numTests!=0?(currentRenderingTime-perfectRenderingTime)/numTests:0; // currentRenderingTime-perfRendering: // float result=currentRenderingTime-perfectRenderingTime; float result=numPoly>0?perfectRenderingTime*1000/numPoly:0; // std::cout <<currentRenderingTime<<"-"<<perfectRenderingTime<<"="<<result<<"\t"<<numTests<<"\n"; // std::cout <<numVBO<<":"<<geoNodesInVisibleGroupNodes.size()<<"\n"; // float result=perfectRenderingTime; // values.push_back(currentRenderingTime); // values.push_back(perfectRenderingTime); values->push_back(new Util::_NumberAttribute<float>(result)); // if(mode==SINGLE_VALUE){ // if(result>renderingTime || renderingTime==0) // renderingTime=result; // }else{ // values.push_back(result); // } // renderingTime=0; }
//! (internal) Main culling method State::stateResult_t OccRenderer::performCulling(FrameContext & context,Node * rootNode, const RenderParam & rp){ if(mode==MODE_UNCONDITIONED){ // destroy temporal coherence frameNumber++; } frameNumber++; updateNodeInformation(context,rootNode); // ??? // used for statistics unsigned int tests=0; int testsVisible=0; int testsInvisible=0; int occludedGeometryNodes=0; Statistics & statistics = context.getStatistics(); RenderParam childParam = rp + USE_WORLD_MATRIX; const Geometry::Vec3 camPos=context.getCamera()->getWorldOrigin(); // NodeDistancePriorityQueue_F2B distanceQueue(camPos); NodeDistancePriorityQueue_F2B distanceQueue(camPos); { // add root node's children const auto children = getChildNodes(rootNode); for(auto & child : children) { distanceQueue.push(child); } } std::queue<std::pair<Rendering::OcclusionQuery, Node *>> queryQueue; // bool wasIdle=true; int idleCount=0; while ( (!distanceQueue.empty()) || (!queryQueue.empty() ) ) { bool idle=true; while ( !queryQueue.empty() && queryQueue.front().first.isResultAvailable() ) { idle=false; const OcclusionQuery & currentQuery = queryQueue.front().first; unsigned int result = currentQuery.getResult(); Node * node = queryQueue.front().second; queryQueue.pop(); NodeInfo * nodeInfo = getNodeInfo(node); // Node is visible? if (result>0 ) { statistics.pushEvent(Statistics::EVENT_TYPE_END_TEST_VISIBLE,nodeInfo->getActualSubtreeComplexity()); testsVisible++; if (node->isClosed()) { // mark parents as visible Node * n=node; NodeInfo * ni=nodeInfo; while( ni->getVisibleFrameNumber()!=frameNumber){ ni->setVisibleFrameNumber(frameNumber); n=n->getParent(); if(n==nullptr || n==rootNode) break; ni=getNodeInfo(n); } } nodeInfo->setVisibleFrameNumber(frameNumber); // haben wir schon bearbeitet? -> Weiter... if (nodeInfo->getProcessedFrameNumber()==frameNumber) continue; //// if(node->visibleFrameNumber != (frameNumber-1)){ ???? // Process node processNode(context,node,nodeInfo,distanceQueue,childParam); //// } }// Node is fully occluded? else { testsInvisible++; statistics.pushEvent(Statistics::EVENT_TYPE_END_TEST_INVISIBLE, nodeInfo->getActualSubtreeComplexity()); // not processed yet? if (nodeInfo->getProcessedFrameNumber()!=frameNumber) { // TODO: Store and propagate in tree. occludedGeometryNodes+=collectNodesInFrustum<GeometryNode>(node,context.getCamera()->getFrustum()).size(); // mark the node as processed nodeInfo->setProcessedFrameNumber(frameNumber); } // In diesem Frame verdeckt worden? (dann haben wir nicht mit der Bearbeitung gewartet und // die Kinder liegen bereits in der distanceQueue; die sollten jetzt �bersprungen werden) if ( nodeInfo->getVisibleFrameNumber() == (frameNumber-1) ) { if (!node->isClosed()) { const auto children = getChildNodes(node); for(auto & child : children) { getNodeInfo(child)->setProcessedFrameNumber(frameNumber); // TODO: Check if ancestors have to be removed too. } } } } } // ... if ( ! distanceQueue.empty()) { idle=false; Node * node=distanceQueue.top(); NodeInfo * nodeInfo=getNodeInfo(node); distanceQueue.pop(); // If the current node has already been processed, then continue. if (nodeInfo->getProcessedFrameNumber()==frameNumber ) continue; // ||node->isEmpty() // // skip empty subtrees // does never happen (checked in processNode) // if( nodeInfo->getActualSubtreeComplexity() == 0){ // nullBoxes++; // continue; // } // Kamera innerhalb der (um die nearplane vergroesserte) Box? -> immer sichtbar // [2008-01-04_CJ] Bugfix: added nearplane addition; could result in dissapearing scene-parts. Geometry::Box extendedBox=node->getWorldBB(); //node->getGeometryBB(); extendedBox.resizeAbs(context.getCamera()->getNearPlane()); if (extendedBox.contains(camPos)) { nodeInfo->setVisibleFrameNumber(frameNumber); // Process node processNode(context,node,nodeInfo,distanceQueue,childParam); continue; } // !IS_INSIDE_FRUSTUM(node) if ( nodeInfo->getActualFrustumStatus()== Geometry::Frustum::OUTSIDE) continue; // [MODE_OPT_CULLING] For optimal culling, skip all unnecessary tests if(mode==MODE_OPT_CULLING && nodeInfo->getVisibleFrameNumber() == (frameNumber-1)){ nodeInfo->setVisibleFrameNumber(frameNumber); // Process node processNode(context,node,nodeInfo,distanceQueue,childParam); continue; } // if query reasonable // TODO: Something missing here? { // start occlusion test for the current node Rendering::OcclusionQuery query; Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext()); query.begin(); Rendering::drawFastAbsBox(context.getRenderingContext(), node->getWorldBB()); query.end(); Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext()); tests++; queryQueue.emplace(std::move(query), node); statistics.pushEvent(Statistics::EVENT_TYPE_START_TEST, nodeInfo->getActualSubtreeComplexity()); } // if the current node was visible in the last frame, // then assume that it is also visible in this frame and process it. if (nodeInfo->getVisibleFrameNumber() == (frameNumber-1) ) { // Process node processNode(context,node,nodeInfo,distanceQueue,childParam); } } // else{ // waiting // } if (idle) { statistics.pushEvent(Statistics::EVENT_TYPE_IDLE, idleCount++); } else { idleCount = 0; } } statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestCounter(), tests); statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestVisibleCounter(), testsVisible); statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestInvisibleCounter(), testsInvisible); statistics.addValue(OcclusionCullingStatistics::instance(statistics).getCulledGeometryNodeCounter(), occludedGeometryNodes); statistics.pushEvent(Statistics::EVENT_TYPE_FRAME_END,0.3); return State::STATE_SKIP_RENDERING; }
State::stateResult_t PhotonRenderer::doEnableState(FrameContext & context, Node * node, const RenderParam & rp){ #ifdef MINSG_THESISSTANISLAW_GATHER_STATISTICS Rendering::RenderingContext::finish(); _timer.reset(); #endif // MINSG_THESISSTANISLAW_GATHER_STATISTICS if(!_photonSampler){ WARN("No PhotonSampler present in PhotonRenderer!"); return State::stateResult_t::STATE_SKIPPED; } if(!_approxScene){ WARN("No approximated Scene present in PhotonRenderer!"); return State::stateResult_t::STATE_SKIPPED; } auto& rc = context.getRenderingContext(); rc.setImmediateMode(true); rc.applyChanges(); if(_fboChanged){ if(!initializeFBO(rc)){ WARN("Could not initialize FBO for PhotonRenderer!"); return State::stateResult_t::STATE_SKIPPED; } _fboChanged = false; } RenderParam newRp; rc.pushAndSetFBO(_fbo.get()); rc.clearDepth(1.0f); rc.applyChanges(); for(int32_t i = 0; i < _photonSampler->getPhotonNumber(); i++){ _fbo->setDrawBuffers(2); rc.pushAndSetShader(_indirectLightShader.get()); _lightPatchRenderer->bindTBO(rc, true, false); _photonSampler->bindPhotonBuffer(1); context.pushAndSetCamera(_photonCamera.get()); _indirectLightShader->setUniform(rc, Rendering::Uniform("photonID", i)); rc.clearDepth(1.0f); rc.clearColor(Util::Color4f(0.f, 0.f, 0.f, 0.f)); _approxScene->display(context, newRp); context.popCamera(); _photonSampler->unbindPhotonBuffer(1); _lightPatchRenderer->unbindTBO(rc); rc.popShader(); // Accumulate all pixel values in one photon _fbo->setDrawBuffers(0); rc.pushAndSetShader(_accumulationShader.get()); _accumulationShader->setUniform(rc, Rendering::Uniform("photonID", i)); _accumulationShader->setUniform(rc, Rendering::Uniform("samplingWidth", static_cast<int>(_samplingWidth))); _accumulationShader->setUniform(rc, Rendering::Uniform("samplingHeight", static_cast<int>(_samplingHeight))); _photonSampler->bindPhotonBuffer(1); rc.clearDepth(1.0f); Rendering::TextureUtils::drawTextureToScreen(rc, Geometry::Rect_i(0, 0, _samplingWidth, _samplingHeight), *_indirectLightTexture.get(), Geometry::Rect_f(0.0f, 0.0f, 1.0f, 1.0f)); _photonSampler->unbindPhotonBuffer(1); rc.popShader(); } rc.popFBO(); rc.setImmediateMode(false); // rc.pushAndSetShader(nullptr); // Rendering::TextureUtils::drawTextureToScreen(rc, Geometry::Rect_i(0, 0, _samplingWidth, _samplingHeight), *(_indirectLightTexture.get()), Geometry::Rect_f(0.0f, 0.0f, 1.0f, 1.0f)); // rc.popShader(); // return State::stateResult_t::STATE_SKIP_RENDERING; #ifdef MINSG_THESISSTANISLAW_GATHER_STATISTICS Rendering::RenderingContext::finish(); _timer.stop(); auto& stats = context.getStatistics(); Statistics::instance(stats).addPhotonRendererTime(stats, _timer.getMilliseconds()); #endif // MINSG_THESISSTANISLAW_GATHER_STATISTICS return State::stateResult_t::STATE_OK; }
//! ---|> [State] State::stateResult_t CHCRenderer::doEnableState(FrameContext & context,Node * rootNode, const RenderParam & rp){ if(rp.getFlag(SKIP_RENDERER)) return State::STATE_SKIPPED; if(debugShowVisible){ std::deque<Node *> nodes; { const auto children = getChildNodes(rootNode); nodes.insert(nodes.end(), children.begin(), children.end()); } while(!nodes.empty()){ Node& node = *nodes.front(); nodes.pop_front(); auto& nodeInfo = getNodeInfo(node); if(nodeInfo.frameNr == frameNr && nodeInfo.visible){ if(node.isClosed()) context.displayNode(&node,rp); else { const auto children = getChildNodes(&node); nodes.insert(nodes.end(), children.begin(), children.end()); } } } }else{ ++frameNr; // used for statistics unsigned int stat_numTests = 0; unsigned int stat_numTestsInvisible = 0; unsigned int stat_numTestsVisible = 0; Statistics & statistics = context.getStatistics(); RenderParam childParam = rp + USE_WORLD_MATRIX; const auto& camera = *context.getCamera(); const Geometry::Vec3 camPos = camera.getWorldOrigin(); const float bbEnlargement = camera.getNearPlane(); NodeDistancePriorityQueue_F2B distanceQueue(camPos); std::queue<std::pair<Rendering::OcclusionQuery, Node*>> queryQueue; const auto traverseNode = [&](Node& node){ if( node.isClosed() ){ // leaf node context.displayNode(&node, childParam ); }else{ for(auto & child : getChildNodes(&node)) distanceQueue.push(child); } }; const auto pullUpVisibility = [&](Node& node){ for(Node* n=&node; n&&n!=rootNode; n = n->getParent()){ auto& nodeInfo = getNodeInfo(*n); if(nodeInfo.frameNr == frameNr && nodeInfo.visible) break; nodeInfo.visible = true; nodeInfo.frameNr = frameNr; }; }; const auto startQuery = [&](Node& node,const Geometry::Box& worldBoundingBox){ Rendering::OcclusionQuery query; Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext()); query.begin(); Rendering::drawAbsBox(context.getRenderingContext(), worldBoundingBox ); query.end(); Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext()); return std::make_pair(std::move(query),&node); }; traverseNode(*rootNode); while(!distanceQueue.empty() || !queryQueue.empty()){ // ---- PART 1: process finished occlusion queries while( !queryQueue.empty() && (distanceQueue.empty() || queryQueue.front().first.isResultAvailable()) ){ if( queryQueue.front().first.getResult()>0 ){ ++stat_numTestsVisible; statistics.pushEvent( Statistics::EVENT_TYPE_END_TEST_VISIBLE, 1); Node& node = *queryQueue.front().second; pullUpVisibility(node); auto& nodeInfo = getNodeInfo( node ); if( !nodeInfo.wasVisible ) traverseNode(node); }else{ ++stat_numTestsInvisible; statistics.pushEvent( Statistics::EVENT_TYPE_END_TEST_INVISIBLE, 1); } queryQueue.pop(); } // ---- PART 2: tree traversal if( !distanceQueue.empty() ){ Node& node = *distanceQueue.top(); distanceQueue.pop(); const Geometry::Box worldBoundingBox = node.getWorldBB(); if (camera.testBoxFrustumIntersection( node.getWorldBB()) == Geometry::Frustum::intersection_t::OUTSIDE) { continue; } Geometry::Box enlargedBox = worldBoundingBox; enlargedBox.resizeAbs( bbEnlargement ); if( enlargedBox.contains(camPos) ){ pullUpVisibility(node); traverseNode(node); continue; } auto& nodeInfo = getNodeInfo( node ); // identify previously visible nodes const bool wasVisible = nodeInfo.frameNr == frameNr-1 && nodeInfo.visible; nodeInfo.wasVisible = wasVisible; // reset node's visibility flag nodeInfo.visible = false; // update node's visited flag nodeInfo.frameNr = frameNr; // test leafs and previously invisible nodes if( node.isClosed() || !wasVisible){ // on testing front // start test ++stat_numTests; statistics.pushEvent(Statistics::EVENT_TYPE_START_TEST, 1); queryQueue.push( std::move(startQuery(node,worldBoundingBox)) ); } // traverse a node unless it was invisible if( wasVisible ) traverseNode( node ); } } statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestVisibleCounter(), stat_numTestsVisible); statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestInvisibleCounter(), stat_numTestsInvisible); statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestCounter(), stat_numTests); } // std::cout << std::endl; return State::STATE_SKIP_RENDERING; }