/** * ---|> [State] */ State::stateResult_t StrangeExampleRenderer::doEnableState(FrameContext & context,Node * node, const RenderParam & rp){ if (rp.getFlag(NO_GEOMETRY) || rp.getFlag(SKIP_RENDERER)) return State::STATE_SKIPPED; /// Collect all nodes in the frustum const auto nodes = collectNodesInFrustum<GeometryNode>(node, context.getCamera()->getFrustum()); if(nodes.size() == 1 && nodes.front() == node) { WARN("This renderer must not be attached to GeometryNodes."); return State::STATE_SKIPPED; } /// Render all nodes with a little extra strangeness Geometry::Matrix4x4 m; float f=0; for(const auto & geoNode : nodes) { float f2=f+Util::Timer::now(); m.setIdentity(); m.scale(1.0+sin( f2)/40.0); m.rotate_deg( sin( f2/0.7)/2.0,0,1,0); context.getRenderingContext().pushMatrix_modelToCamera(); context.getRenderingContext().multMatrix_modelToCamera(m); context.displayNode(geoNode,rp); context.getRenderingContext().popMatrix_modelToCamera(); f+=137.0; } return State::STATE_SKIP_RENDERING; }
State::stateResult_t SkyboxState::doEnableState(FrameContext & context, Node *, const RenderParam & rp) { if (rp.getFlag(NO_GEOMETRY)) { return State::STATE_SKIPPED; } Vec3 pos = context.getCamera()->getWorldOrigin(); Geometry::Matrix4x4 matrix; matrix.translate(pos); context.getRenderingContext().pushMatrix_modelToCamera(); context.getRenderingContext().multMatrix_modelToCamera(matrix); context.getRenderingContext().pushTexture(0); context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, false, Rendering::Comparison::LESS)); context.getRenderingContext().pushAndSetLighting(Rendering::LightingParameters(false)); Geometry::Box box(Geometry::Vec3(0.0f, 0.0f, 0.0f), sideLength); for (uint_fast8_t side = 0; side < 6; ++side) { if (!textures[side].isNull()) { context.getRenderingContext().setTexture(0,textures[side].get()); const Geometry::corner_t * corners = Geometry::Helper::getCornerIndices(static_cast<Geometry::side_t> (side)); // Reverse the corner order because we need the inner surface. Rendering::drawQuad(context.getRenderingContext(), box.getCorner(corners[1]), box.getCorner(corners[0]), box.getCorner(corners[3]), box.getCorner(corners[2]),Util::ColorLibrary::WHITE); } } context.getRenderingContext().popLighting(); context.getRenderingContext().popDepthBuffer(); context.getRenderingContext().popTexture(0); context.getRenderingContext().popMatrix_modelToCamera(); return State::STATE_OK; }
void FakeInstanceNode::doDisplay(FrameContext & frameContext, const RenderParam & rp) { if(fakePrototype.isNull()) { Node::doDisplay(frameContext, rp); return; } auto camera = static_cast<AbstractCameraNode*>(frameContext.getCamera()->clone()); const Geometry::Matrix4x4f & cameraMatrix = frameContext.getCamera()->getWorldTransformationMatrix(); camera->setRelTransformation( fakePrototype->getWorldTransformationMatrix() * getWorldToLocalMatrix() * cameraMatrix); frameContext.pushAndSetCamera(camera); frameContext.displayNode(fakePrototype.get(), rp); frameContext.popCamera(); }
void OccRenderer::updateNodeInformation(FrameContext & context,Node * rootNode)const{ /*** ** Vis ---|> NodeVisitor ***/ struct Vis:public NodeVisitor { const OccRenderer & r; AbstractCameraNode * camera; const Node * rootNode; int insideFrustum; Geometry::Vec3 camPos; Vis(const OccRenderer & _r, const Node * _rootNode, AbstractCameraNode * _camera) : r(_r), camera(_camera), rootNode(_rootNode), insideFrustum(0), camPos(_camera->getWorldOrigin()) {} virtual ~Vis() {} // ---|> NodeVisitor NodeVisitor::status enter(Node * node) override { NodeInfo * info=r.getNodeInfo(node); info->setActualSubtreeComplexity(0); // the current subtree is completely inside the frustum, so we need not to test inside this subtree if(insideFrustum>0){ info->setActualFrustumStatus(Geometry::Frustum::INSIDE); insideFrustum++; }else{ int i=camera->testBoxFrustumIntersection( node->getWorldBB()); info->setActualFrustumStatus(i); if(i==Geometry::Frustum::OUTSIDE){ return NodeVisitor::BREAK_TRAVERSAL; }else if(i==Geometry::Frustum::INSIDE){ insideFrustum++; } } if(node->isClosed() && node!=rootNode){ unsigned int c = insideFrustum > 0 ? countTriangles(node) : countTrianglesInFrustum(node, camera->getFrustum()); info->increaseActualSubtreeComplexity( c ); return BREAK_TRAVERSAL; } return CONTINUE_TRAVERSAL; } // ---|> NodeVisitor NodeVisitor::status leave(Node * node) override { if(insideFrustum>0){ insideFrustum--; } unsigned int complexity=r.getNodeInfo(node)->getActualSubtreeComplexity(); if(complexity>0 && rootNode!=node && node->hasParent()){ NodeInfo * pinfo=r.getNodeInfo(node->getParent()); pinfo->increaseActualSubtreeComplexity(complexity); } return CONTINUE_TRAVERSAL; } } visitor(*this,rootNode,context.getCamera()); rootNode->traverse(visitor); return; }
State::stateResult_t SurfelRenderer::doEnableState(FrameContext & context, Node * node, const RenderParam & rp) { State::stateResult_t result = NodeRendererState::doEnableState(context,node,rp); if( result == State::STATE_OK ){ CameraNode* camera = dynamic_cast<CameraNode*>( context.getCamera() ); if(camera){ // else: an orthographic camera is used; just re-use the previous values. cameraOrigin = camera->getWorldOrigin(); projectionScale = camera->getWidth() / (std::tan((camera->getRightAngle()-camera->getLeftAngle()).rad()*0.5f)*2.0f); } } return result; }
State::stateResult_t OccRenderer::showCulled(FrameContext & context,Node * rootNode, const RenderParam & rp){ std::deque<Node *> nodes; nodes.push_back(rootNode); while(!nodes.empty()){ Node * node=nodes.front(); nodes.pop_front(); NodeInfo * nInfo=getNodeInfo(node); if(!conditionalFrustumTest(context.getCamera()->getFrustum(), node->getWorldBB(), rp)) continue; else if(node->isClosed() ){ if(nInfo->getVisibleFrameNumber()!=frameNumber) context.displayNode(node,rp); }else { const auto children = getChildNodes(node); nodes.insert(nodes.end(), children.begin(), children.end()); } } return State::STATE_SKIP_RENDERING; }
bool VisibilitySubdivisionRenderer::renderCellSubset(FrameContext & context, cell_ptr cell, uint32_t budgetBegin, uint32_t budgetEnd) { try { const auto & vv = getVV(cell); std::vector<std::pair<float, object_ptr>> displayObjects; const uint32_t maxIndex = vv.getIndexCount(); for(uint_fast32_t index = 0; index < maxIndex; ++index) { if(vv.getBenefits(index) == 0) { continue; } const VisibilityVector::costs_t costs = vv.getCosts(index); const VisibilityVector::benefits_t benefits = vv.getBenefits(index); const float score = static_cast<float>(costs) / static_cast<float>(benefits); displayObjects.emplace_back(score, vv.getNode(index)); } const Geometry::Frustum & frustum = context.getCamera()->getFrustum(); uint32_t renderedTriangles = 0; std::sort(displayObjects.begin(), displayObjects.end()); for(const auto & objectRatioPair : displayObjects) { object_ptr o = objectRatioPair.second; Geometry::Frustum::intersection_t result = frustum.isBoxInFrustum(o->getWorldBB()); if (result == Geometry::Frustum::intersection_t::INSIDE || result == Geometry::Frustum::intersection_t::INTERSECT) { if(renderedTriangles >= budgetBegin) { context.displayNode(o, 0); } renderedTriangles += o->getTriangleCount(); } if (budgetEnd != 0 && renderedTriangles >= budgetEnd) { break; } } } catch(...) { // Invalid information. => Fall back to standard rendering. return false; } return true; }
void ColorVisibilityEvaluator::measure(FrameContext & context, Node & node, const Geometry::Rect & rect) { Rendering::RenderingContext & rCtxt = context.getRenderingContext(); // ### Set up textures for the framebuffer object. ### const uint32_t width = static_cast<uint32_t> (rect.getWidth()); const uint32_t height = static_cast<uint32_t> (rect.getHeight()); if (colorTexture == nullptr || width != static_cast<uint32_t> (colorTexture->getWidth()) || height != static_cast<uint32_t> (colorTexture->getHeight())) { // (Re-)Create textures with correct dimension. rCtxt.pushAndSetFBO(fbo.get()); fbo->detachColorTexture(context.getRenderingContext()); fbo->detachDepthTexture(context.getRenderingContext()); rCtxt.popFBO(); colorTexture = Rendering::TextureUtils::createStdTexture(width, height, true); depthTexture = Rendering::TextureUtils::createDepthTexture(width, height); // Bind textures to FBO. rCtxt.pushAndSetFBO(fbo.get()); fbo->attachColorTexture(context.getRenderingContext(),colorTexture.get()); fbo->attachDepthTexture(context.getRenderingContext(),depthTexture.get()); rCtxt.popFBO(); } // ### Render the scene into a framebuffer object. ### rCtxt.pushAndSetFBO(fbo.get()); rCtxt.pushAndSetShader(getShader()); rCtxt.clearScreen(Util::Color4f(0.0f, 0.0f, 0.0f, 0.0f)); // Color counter for assignment of unique colors to triangles. // Background is black (color 0). int32_t currentColor = 1; // Collect potentially visible geometry nodes. const auto geoNodes = collectNodesInFrustum<GeometryNode>(&node, context.getCamera()->getFrustum()); for(const auto & geoNode : geoNodes) { getShader()->setUniform(rCtxt, Rendering::Uniform("colorOffset", currentColor)); context.displayNode(geoNode, USE_WORLD_MATRIX | NO_STATES); currentColor += geoNode->getTriangleCount(); } rCtxt.popShader(); rCtxt.popFBO(); // ### Read texture and analyze colors. ### // Map from colors to number of occurrences. std::map<uint32_t, uint32_t> colorUsage; // Current color is compared with the previous color. If they match, the local count variable is used as cache before insertion into map is performed. uint32_t lastColor = 0; uint32_t lastCount = 0; colorTexture->downloadGLTexture(rCtxt); const uint32_t * texData = reinterpret_cast<const uint32_t *> (colorTexture->openLocalData(rCtxt)); const uint32_t numPixels = width * height; for (uint_fast32_t p = 0; p < numPixels; ++p) { const uint32_t & color = texData[p]; if (color == 0) { // Ignore background. continue; } if (color == lastColor) { ++lastCount; continue; } else { // Insert previous color. if (lastColor != 0) { increaseColorUsage(lastColor, lastCount, colorUsage); } lastColor = color; lastCount = 1; } } if (lastColor != 0) { increaseColorUsage(lastColor, lastCount, colorUsage); } if (mode == SINGLE_VALUE) { numTrianglesVisible += colorUsage.size(); } else { values->push_back(Util::GenericAttribute::createNumber(colorUsage.size())); } }
//! ---|> 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; }
State::stateResult_t VisibilitySubdivisionRenderer::doEnableState( FrameContext & context, Node *, const RenderParam & rp) { if (rp.getFlag(SKIP_RENDERER)) { return State::STATE_SKIPPED; } if (viSu == nullptr) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } // [AccumRendering] if(accumRenderingEnabled){ // camera moved? -> start new frame const Geometry::Matrix4x4 & newCamMat=context.getCamera()->getWorldTransformationMatrix(); if(newCamMat!=lastCamMatrix){ lastCamMatrix = newCamMat; startRuntime=0; } }else{ startRuntime=0; } // ---- uint32_t renderedTriangles = 0; if (hold) { for (const auto & object : holdObjects) { if (debugOutput) { debugDisplay(renderedTriangles, object, context, rp); } else { context.displayNode(object, rp); } } return State::STATE_SKIP_RENDERING; } Geometry::Vec3 pos = context.getCamera()->getWorldOrigin(); bool refreshCache = false; // Check if cached cell can be used. if (currentCell == nullptr || !currentCell->getBB().contains(pos)) { currentCell = viSu->getNodeAtPosition(pos); refreshCache = true; } if (currentCell == nullptr || !currentCell->isLeaf()) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } if (refreshCache) { try { const auto & vv = getVV(currentCell); const uint32_t maxIndex = vv.getIndexCount(); objects.clear(); objects.reserve(maxIndex); for(uint_fast32_t index = 0; index < maxIndex; ++index) { if(vv.getBenefits(index) == 0) { continue; } const VisibilityVector::costs_t costs = vv.getCosts(index); const VisibilityVector::benefits_t benefits = vv.getBenefits(index); const float score = static_cast<float>(costs) / static_cast<float>(benefits); objects.emplace_back(score, vv.getNode(index)); } } catch(...) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } if (displayTexturedDepthMeshes) { #ifdef MINSG_EXT_OUTOFCORE for (const auto & depthMesh : depthMeshes) { OutOfCore::getCacheManager().setUserPriority(depthMesh.get(), 0); } #endif /* MINSG_EXT_OUTOFCORE */ depthMeshes.clear(); depthMeshes.reserve(6); textures.clear(); textures.reserve(6); const std::string dmDirectionStrings[6] = { "-dir_x1_y0_z0", "-dir_x-1_y0_z0", "-dir_x0_y1_z0", "-dir_x0_y-1_z0", "-dir_x0_y0_z1", "-dir_x0_y0_z-1" }; for (auto & dmDirectionString : dmDirectionStrings) { Util::GenericAttribute * attrib = currentCell->getAttribute("DepthMesh" + dmDirectionString); if (attrib == nullptr) { continue; } Util::FileName dmMeshPath(attrib->toString()); Util::Reference<Rendering::Mesh> dmMesh; #ifdef MINSG_EXT_OUTOFCORE Util::GenericAttribute * bbAttrib = currentCell->getAttribute("DepthMesh" + dmDirectionString + "-bounds"); if (bbAttrib == nullptr) { WARN("Found depth mesh with no bounding box."); continue; } std::vector<float> bbValues = Util::StringUtils::toFloats(bbAttrib->toString()); FAIL_IF(bbValues.size() != 6); const Geometry::Box meshBB(Geometry::Vec3(bbValues[0], bbValues[1], bbValues[2]), bbValues[3], bbValues[4], bbValues[5]); dmMesh = OutOfCore::addMesh(dmMeshPath, meshBB); #else /* MINSG_EXT_OUTOFCORE */ dmMesh = Rendering::Serialization::loadMesh(dmMeshPath); #endif /* MINSG_EXT_OUTOFCORE */ depthMeshes.emplace_back(dmMesh); // Count the depth mesh here already. renderedTriangles += dmMesh->getPrimitiveCount(); Util::GenericAttribute * texAttrib = currentCell->getAttribute("Texture" + dmDirectionString); if (texAttrib == nullptr) { continue; } Util::FileName texturePath(texAttrib->toString()); Util::Reference<Rendering::Texture> texture = Rendering::Serialization::loadTexture(texturePath); if (texture.isNull()) { WARN("Loading texture for depth mesh failed."); continue; } textures.emplace_back(texture); } } } const Geometry::Frustum & frustum = context.getCamera()->getFrustum(); holdObjects.clear(); holdObjects.reserve(objects.size()); std::sort(objects.begin(), objects.end()); for(const auto & ratioObjectPair : objects) { object_ptr o = ratioObjectPair.second; #ifdef MINSG_EXT_OUTOFCORE OutOfCore::getCacheManager().setUserPriority(o->getMesh(), 5); #endif /* MINSG_EXT_OUTOFCORE */ if (conditionalFrustumTest(frustum, o->getWorldBB(), rp)) { // [AccumRendering] // skip geometry rendered in the last frame if(renderedTriangles<startRuntime){ renderedTriangles += o->getTriangleCount(); continue; } // ---- if (debugOutput) { debugDisplay(renderedTriangles, o, context, rp); } else { context.displayNode(o, rp); renderedTriangles += o->getTriangleCount(); } holdObjects.push_back(o); } if (maxRuntime != 0 && renderedTriangles >= startRuntime+maxRuntime) { break; } } // Draw the textured depth meshes at the end. if (displayTexturedDepthMeshes) { context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(polygonOffsetFactor, polygonOffsetUnits)); auto texIt = textures.cbegin(); for (const auto & depthMesh : depthMeshes) { context.getRenderingContext().pushAndSetShader(getTDMShader()); context.getRenderingContext().pushAndSetTexture(0,texIt->get()); if (conditionalFrustumTest(frustum, depthMesh->getBoundingBox(), rp)) { context.displayMesh(depthMesh.get()); } context.getRenderingContext().popTexture(0); context.getRenderingContext().popShader(); #ifdef MINSG_EXT_OUTOFCORE OutOfCore::getCacheManager().setUserPriority(depthMesh.get(), 2); #endif /* MINSG_EXT_OUTOFCORE */ ++texIt; } context.getRenderingContext().popPolygonOffset(); } // [AccumRendering] startRuntime=renderedTriangles; // ---- return State::STATE_SKIP_RENDERING; }
//! (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 TwinPartitionsRenderer::doEnableState(FrameContext & context, Node *, const RenderParam & rp) { if (rp.getFlag(SKIP_RENDERER)) { return State::STATE_SKIPPED; } if (data == nullptr) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } const Geometry::Vec3f pos = context.getCamera()->getWorldOrigin(); // Check if cached cell can be used. if (currentCell == INVALID_CELL || !data->cells[currentCell].bounds.contains(pos)) { // Search the cell that contains the camera position. bool cellFound = false; const uint32_t cellCount = data->cells.size(); for (uint_fast32_t cell = 0; cell < cellCount; ++cell) { if (data->cells[cell].bounds.contains(pos)) { // #ifdef MINSG_EXT_OUTOFCORE // // Set new priorities if the current cell changes. // if (currentCell != cell) { // // Low priority for old depth mesh. // if (currentCell != INVALID_CELL) { // for(std::vector<uint32_t>::const_iterator it = data->cells[currentCell].surroundingIds.begin(); it != data->cells[currentCell].surroundingIds.end(); ++it) { // Rendering::Mesh * depthMesh = data->depthMeshes[*it].get(); // OutOfCore::getCacheManager().setUserPriority(depthMesh, 0); // } // } // // High priority for new depth mesh. // { // for(std::vector<uint32_t>::const_iterator it = data->cells[cell].surroundingIds.begin(); it != data->cells[cell].surroundingIds.end(); ++it) { // Rendering::Mesh * depthMesh = data->depthMeshes[*it].get(); // OutOfCore::getCacheManager().setUserPriority(depthMesh, 20); // } // } // // Low priority for meshes visible from the old cell. // if (currentCell != INVALID_CELL) { // const uint32_t oldVisibleSetIndex = data->cells[currentCell].visibleSetId; // const PartitionsData::visible_set_t & oldVisibleSet = data->visibleSets[oldVisibleSetIndex]; // for (PartitionsData::visible_set_t::const_iterator it = oldVisibleSet.begin(); it != oldVisibleSet.end(); ++it) { // Rendering::Mesh * mesh = data->objects[it->second].get(); // OutOfCore::getCacheManager().setUserPriority(mesh, 0); // } // } // // High priority for meshes visible from the new cell. // { // const uint32_t visibleSetIndex = data->cells[cell].visibleSetId; // const PartitionsData::visible_set_t & visibleSet = data->visibleSets[visibleSetIndex]; // for (PartitionsData::visible_set_t::const_iterator it = visibleSet.begin(); it != visibleSet.end(); ++it) { // Rendering::Mesh * mesh = data->objects[it->second].get(); // OutOfCore::getCacheManager().setUserPriority(mesh, 10); // } // } // } // #endif /* MINSG_EXT_OUTOFCORE */ // Load new textures. textures.clear(); if(drawTexturedDepthMeshes) { textures.reserve(6); for(auto & elem : data->cells[cell].surroundingIds) { const std::string & textureFile = data->textureFiles[elem]; Util::Reference<Rendering::Texture> texture = Rendering::Serialization::loadTexture(Util::FileName(textureFile)); if(texture == nullptr) { WARN("Failed to load texture for depth mesh."); } else { textures.push_back(texture); } } } currentCell = cell; cellFound = true; break; } } if (!cellFound) { // Camera outside view space. currentCell = INVALID_CELL; return State::STATE_SKIPPED; } } uint32_t renderedTriangles = 0; const uint32_t visibleSetIndex = data->cells[currentCell].visibleSetId; const PartitionsData::visible_set_t & visibleSet = data->visibleSets[visibleSetIndex]; if(drawTexturedDepthMeshes) { for(auto & elem : data->cells[currentCell].surroundingIds) { Rendering::Mesh * depthMesh = data->depthMeshes[elem].get(); // Count the depth meshes here already. renderedTriangles += depthMesh->getPrimitiveCount(); } } const Geometry::Frustum & frustum = context.getCamera()->getFrustum(); /*float minDist = 9999999.0f; float maxDist = 0.0f; float prioSum = 0.0f; uint_fast32_t objectCounter = 0; for (PartitionsData::visible_set_t::const_iterator it = visibleSet.begin(); it != visibleSet.end(); ++it) { Rendering::Mesh * mesh = data->objects[it->second].get(); float dist = mesh->getBoundingBox().getDistance(pos); minDist = std::min(dist, minDist); maxDist = std::max(dist, maxDist); if(objectCounter < 10) { prioSum += it->first; ++objectCounter; } } std::ofstream output("twinOutput.tsv", ios_base::out | ios_base::app); output << currentCell << '\t' << data->cells[currentCell].bounds.getDiameter() << '\t' << (data->cells[currentCell].bounds.getCenter() - pos).length() << '\t' << visibleSet.begin()->first << '\t' << visibleSet.rbegin()->first << '\t' << minDist << '\t' << maxDist << '\t' << prioSum << '\t'; for(std::vector<uint32_t>::const_iterator it = data->cells[currentCell].surroundingIds.begin(); it != data->cells[currentCell].surroundingIds.end(); ++it) { Rendering::Mesh * depthMesh = data->depthMeshes[*it].get(); const Geometry::Box & depthMeshBB = depthMesh->getBoundingBox(); const Geometry::Vec3f originalDirection = (depthMeshBB.getCenter() - data->cells[currentCell].bounds.getCenter()).normalize(); const Geometry::Vec3f currentDirection = (depthMeshBB.getCenter() - pos).normalize(); const float angle = currentDirection.dot(originalDirection); const bool visible = (frustum.isBoxInFrustum(depthMeshBB) != Frustum::OUTSIDE); output << '\t'; if(visible) { output << angle ; } else { output << "NA"; } } for(uint_fast32_t i = data->cells[currentCell].surroundingIds.size(); i < 6; ++i) { output << "\tNA"; } output << std::endl; output.close();*/ for (auto & elem : visibleSet) { Rendering::Mesh * mesh = data->objects[elem.second].get(); if (conditionalFrustumTest(frustum, mesh->getBoundingBox(), rp)) { context.displayMesh(mesh); renderedTriangles += mesh->getPrimitiveCount(); } if(rp.getFlag(BOUNDING_BOXES)) { Rendering::drawWireframeBox(context.getRenderingContext(), mesh->getBoundingBox(), Util::ColorLibrary::RED); } if (maxRuntime != 0 && renderedTriangles >= maxRuntime) { break; } } // Draw the textured depth meshes at the end. if(drawTexturedDepthMeshes) { context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(polygonOffsetFactor, polygonOffsetUnits)); context.getRenderingContext().pushAndSetShader(getTDMShader()); context.getRenderingContext().pushTexture(0); auto texIt = textures.begin(); for(auto & elem : data->cells[currentCell].surroundingIds) { Rendering::Mesh * depthMesh = data->depthMeshes[elem].get(); Rendering::Texture * texture = texIt->get(); context.getRenderingContext().setTexture(0, texture); if (conditionalFrustumTest(frustum, depthMesh->getBoundingBox(), rp)) { context.displayMesh(depthMesh); } ++texIt; } context.getRenderingContext().popTexture(0); context.getRenderingContext().popShader(); context.getRenderingContext().popPolygonOffset(); } return State::STATE_SKIP_RENDERING; }
//! ---|> [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; }
//! ---|> Evaluator void VisibilityEvaluator::measure(FrameContext & context,Node & node,const Geometry::Rect & /*r*/) { // first pass - fill depth buffer. context.getRenderingContext().clearScreen(Util::Color4f(0.9f, 0.9f, 0.9f, 1.0f)); node.display(context,USE_WORLD_MATRIX|FRUSTUM_CULLING); if (getMaxValue()->toInt() == 0.0) { setMaxValue_i(collectNodes<GeometryNode>(&node).size()); } if (mode==SINGLE_VALUE) { // collect geometry nodes in frustum auto objectsInVFList = collectNodesInFrustum<GeometryNode>(&node, context.getCamera()->getFrustum()); for(const auto & geoNode : objectsInVFList) { objectsInVF[reinterpret_cast<uintptr_t>(geoNode)] = geoNode; } // setup occlusion queries int numQueries=objectsInVFList.size(); if (numQueries==0) return; auto queries = new Rendering::OcclusionQuery[numQueries]; { // optional second pass: test bounding boxes context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, true, Rendering::Comparison::LEQUAL)); context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(0.0f, -1.0f)); int i=0; // start queries Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext()); for(const auto & geoNode : objectsInVFList) { queries[i].begin(); Rendering::drawAbsBox(context.getRenderingContext(), geoNode->getWorldBB() ); queries[i].end(); ++i; } Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext()); i=0; // get results for(auto & geoNode : objectsInVFList) { if (queries[i].getResult() == 0 && !geoNode->getWorldBB().contains(context.getCamera()->getWorldOrigin()) ) { geoNode=nullptr; } ++i; } context.getRenderingContext().popPolygonOffset(); context.getRenderingContext().popDepthBuffer(); } { // third pass: test if nodes are exactly visible context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, true, Rendering::Comparison::EQUAL)); int i=0; // start queries for(const auto & geoNode : objectsInVFList) { if (!geoNode) continue; queries[i].begin(); // render object i context.displayNode(geoNode, USE_WORLD_MATRIX); queries[i].end(); ++i; } i=0; // get results for(const auto & geoNode : objectsInVFList) { if (!geoNode) continue; if (queries[i].getResult() > 0) { visibleObjects[reinterpret_cast<uintptr_t>(geoNode)] = geoNode; } ++i; } context.getRenderingContext().popDepthBuffer(); } delete [] queries; } else {//mode == DIRECTION_VALUES const auto nodes = collectVisibleNodes(&node, context); if(doesCountPolygons()){ uint32_t numPolys=0; for(const auto & n : nodes) { numPolys += n->getTriangleCount(); } values->push_back(new Util::_NumberAttribute<float>(numPolys)); }else{ values->push_back(new Util::_NumberAttribute<float>(nodes.size())); } } }