/** * ---|> [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; }
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(); }
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; }
/** * (internal) */ void OccRenderer::processNode(FrameContext & context,Node * node,NodeInfo * nodeInfo,NodeDistancePriorityQueue_F2B & distanceQueue,const RenderParam & rp){ if (!node->isActive()) return; nodeInfo->setProcessedFrameNumber(frameNumber); if(node->isClosed()){ context.displayNode(node, rp ); }else{ const auto children = getChildNodes(node); for(auto & child : children){ NodeInfo * i=getNodeInfo(child); if( rp.getFlag(FRUSTUM_CULLING) && i->getActualFrustumStatus()==Geometry::Frustum::OUTSIDE) //context.getCamera()->testBoxFrustumIntersection( (*it)->getWorldBB()) == Frustum::OUTSIDE ) continue; if( i->getActualSubtreeComplexity() == 0){ continue; } distanceQueue.push(child); } } }
void VisibilitySubdivisionRenderer::debugDisplay(uint32_t & renderedTriangles, object_ptr object, FrameContext & context, const RenderParam & rp) { const Util::Color4f specular(0.1f, 0.1f, 0.1f, 1.0f); const float ratio = static_cast<float> (renderedTriangles) / static_cast<float> (maxRuntime); // Gradient from light blue to red. Util::Color4f color(ratio, 0.5f - 0.5f * ratio, 1.0f - ratio, 1.0f); Rendering::MaterialParameters material; material.setAmbient(color); material.setDiffuse(color); material.setSpecular(specular); material.setShininess(64.0f); context.getRenderingContext().pushAndSetMaterial(material); context.displayNode(object, rp); context.getRenderingContext().popMaterial(); renderedTriangles += object->getTriangleCount(); }
//! ---|> [State] State::stateResult_t EnvironmentState::doEnableState(FrameContext & context, Node * /*node*/, const RenderParam & rp) { if (rp.getFlag(NO_GEOMETRY)) return State::STATE_SKIPPED; if (!environment.isNull()) { // extract rotation of the camera Geometry::SRT camRotationSrt = context.getRenderingContext().getMatrix_worldToCamera()._toSRT(); camRotationSrt.setTranslation(Geometry::Vec3(0,0,0)); camRotationSrt.setScale(1.0); // render the environment node as seen standing at the origin (0,0,0) but looking in the camera's direction. context.getRenderingContext().pushMatrix_modelToCamera(); context.getRenderingContext().setMatrix_modelToCamera(Geometry::Matrix4x4(camRotationSrt)); context.getRenderingContext().multMatrix_modelToCamera(Geometry::Matrix4x4f(Geometry::SRT(Geometry::Vec3f(0,0,0), context.getWorldFrontVector(), context.getWorldUpVector()))); context.displayNode(environment.get(), rp); context.getRenderingContext().popMatrix_modelToCamera(); } return State::STATE_OK; }
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; }
//! ---|> [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())); } } }
void OverdrawFactorEvaluator::measure(FrameContext & frameContext, Node & node, const Geometry::Rect & rect) { Rendering::RenderingContext & renderingContext = frameContext.getRenderingContext(); // Set up FBO and texture Util::Reference<Rendering::FBO> fbo = new Rendering::FBO; renderingContext.pushAndSetFBO(fbo.get()); Util::Reference<Rendering::Texture> depthStencilTexture = Rendering::TextureUtils::createDepthStencilTexture(rect.getWidth(), rect.getHeight()); fbo->attachDepthStencilTexture(renderingContext, depthStencilTexture.get()); // Disable color and depth writes renderingContext.pushAndSetColorBuffer(Rendering::ColorBufferParameters(false, false, false, false)); renderingContext.pushAndSetDepthBuffer(Rendering::DepthBufferParameters(false, false, Rendering::Comparison::LESS)); // Increase the stencil value for every rendered pixel Rendering::StencilParameters stencilParams; stencilParams.enable(); stencilParams.setFunction(Rendering::Comparison::ALWAYS); stencilParams.setReferenceValue(0); stencilParams.setBitMask(0); stencilParams.setFailAction(Rendering::StencilParameters::INCR); stencilParams.setDepthTestFailAction(Rendering::StencilParameters::INCR); stencilParams.setDepthTestPassAction(Rendering::StencilParameters::INCR); renderingContext.pushAndSetStencil(stencilParams); // Render the node renderingContext.clearStencil(0); frameContext.displayNode(&node, 0); // Reset GL state renderingContext.popStencil(); renderingContext.popDepthBuffer(); renderingContext.popColorBuffer(); // Fetch the texture. depthStencilTexture->downloadGLTexture(renderingContext); renderingContext.popFBO(); Util::Reference<Util::PixelAccessor> stencilAccessor = Rendering::TextureUtils::createStencilPixelAccessor(renderingContext, *depthStencilTexture.get()); std::vector<uint8_t> stencilValues; stencilValues.reserve(rect.getWidth() * rect.getHeight()); for(uint_fast32_t y = 0; y < rect.getHeight(); ++y) { for(uint_fast32_t x = 0; x < rect.getWidth(); ++x) { const uint8_t stencilValue = stencilAccessor->readSingleValueByte(x, y); stencilValues.push_back(stencilValue); } } // // Create and write debug image // { // Util::Reference<Rendering::Texture> colorTexture = Rendering::TextureUtils::createStdTexture(rect.getWidth(), rect.getHeight(), true); // Util::Reference<Util::PixelAccessor> colorAccessor = Rendering::TextureUtils::createColorPixelAccessor(renderingContext, colorTexture.get()); // const auto stencilMinMax = std::minmax_element(stencilValues.cbegin(), stencilValues.cend()); // const auto stencilMin = *stencilMinMax.first; // const auto stencilMax = *stencilMinMax.second; // const double stencilRange = stencilMax - stencilMin; // const double factor = 1.0 / stencilRange; // // Color scheme RdYlBu with 5 of 8 colors from www.colorbrewer2.org // const std::array<Util::Color4f, 5> gradient = { // Util::Color4ub(44, 123, 182, 255), // Util::Color4ub(171, 217, 233, 255), // Util::Color4ub(255, 255, 191, 255), // Util::Color4ub(253, 174, 97, 255), // Util::Color4ub(215, 25, 28, 255) // }; // for(uint_fast32_t y = 0; y < rect.getHeight(); ++y) { // for(uint_fast32_t x = 0; x < rect.getWidth(); ++x) { // const uint8_t stencilValue = stencilValues[y * rect.getWidth() + x]; // if(stencilValue == 0) { // colorAccessor->writeColor(x, y, Util::Color4f(1.0, 1.0, 1.0, 0.0)); // } else { // const double normalizedValue = static_cast<double>(stencilValue - stencilMin) * factor; // const double gradientPos = normalizedValue * (gradient.size() - 1); // const size_t gradientIndex = std::floor(gradientPos); // colorAccessor->writeColor(x, y, Util::Color4f(gradient[gradientIndex], gradient[gradientIndex + 1], gradientPos - gradientIndex)); // } // } // } // Rendering::Serialization::saveTexture(renderingContext, colorTexture.get(), Util::FileName("stencil.png")); // } if(resultRemoveZeroValues) { stencilValues.erase(std::remove(stencilValues.begin(), stencilValues.end(), 0), stencilValues.end()); } uint8_t result = 0; if(!stencilValues.empty()) { if(resultQuantile >= 1.0) { result = *std::max_element(stencilValues.cbegin(), stencilValues.cend()); } else if(resultQuantile <= 0.0) { result = *std::min_element(stencilValues.cbegin(), stencilValues.cend()); } else { const std::size_t quantilePos = resultQuantile * stencilValues.size(); std::nth_element(stencilValues.begin(), std::next(stencilValues.begin(), static_cast<std::ptrdiff_t>(quantilePos)), stencilValues.end()); result = stencilValues[quantilePos]; } } values->push_back(Util::GenericAttribute::createNumber(result)); setMaxValue_i(result); }
/*! @note very important: color cubes of the children must already exist, otherwise there will be a segmentation fault */ void ColorCubeGenerator::processColorCube(FrameContext& context, Node * node, deque<Node*>& children) { const Geometry::Box box = node->getWorldBB(); ColorCube cc; // 1. case: current node's color cube should be processed by drawing Geometry < see processColorCubes(...) > if (children.empty()) { context.getRenderingContext().pushAndSetLighting(Rendering::LightingParameters(true)); context.getRenderingContext().applyChanges(); // render the six sides context.getRenderingContext().pushAndSetFBO(fbo.get()); for (uint8_t _side = 0; _side < 6; ++_side) { // determine the color for each of the 6 faces const Geometry::side_t side = static_cast<Geometry::side_t> (_side); if (!prepareCamera(context, box, side)) continue; context.getRenderingContext().clearScreen(Util::Color4f(0.0f, 0.0f, 0.0f, 0.0f)); context.displayNode(node, USE_WORLD_MATRIX); } context.getRenderingContext().popFBO(); colorTexture->downloadGLTexture(context.getRenderingContext()); //////////// debug // static uint32_t counter=0; // stringstream ss; // ss << "screens/colorcube_" << counter++ << ".png"; // Util::FileName filename(ss.str()); // Rendering::Serialization::saveTexture(context.getRenderingContext(), colorTexture.get(), filename); //////////// end debug // determine the color for each of the 6 faces for (uint8_t _side = 0; _side < 6; ++_side) { const Geometry::side_t side = static_cast<Geometry::side_t> (_side); if (prepareCamera(context, box, side)){ const Color4ub c = calculateColor(colorTexture.get(), camera->getViewport()); //calculate color from texture cc.colors[static_cast<uint8_t> (side)] = c; } else { cc.colors[static_cast<uint8_t> (side)] = Color4ub(0, 0, 0, 0); } } context.getRenderingContext().popLighting(); } else{ context.getRenderingContext().pushAndSetFBO(fbo.get()); // enable the fbo // 2. case: the node is not a closed GroupNode (inner node) for (uint8_t _side = 0; _side < 6; ++_side) { // for each of the six faces Geometry::side_t side = static_cast<Geometry::side_t> (_side); if (!prepareCamera(context, box, side)) continue; context.getRenderingContext().clearScreen(Util::Color4f(0.0f, 0.0f, 0.0f, 0.0f)); context.getRenderingContext().pushAndSetMatrix_modelToCamera( context.getRenderingContext().getMatrix_worldToCamera() ); // draw faces using blending context.getRenderingContext().pushAndSetBlending(Rendering::BlendingParameters(Rendering::BlendingParameters::ONE, Rendering::BlendingParameters::ONE_MINUS_SRC_ALPHA)); context.getRenderingContext().pushAndSetCullFace(Rendering::CullFaceParameters(Rendering::CullFaceParameters::CULL_BACK)); context.getRenderingContext().pushAndSetDepthBuffer(Rendering::DepthBufferParameters(true, false, Rendering::Comparison::LESS)); context.getRenderingContext().pushAndSetLighting(Rendering::LightingParameters(false)); context.getRenderingContext().applyChanges(); distanceQueue_t nodes(side); // distance queue used for sorting the children with color cubes // sort (back-to-front order) the children according to distance of current side to the camera for(const auto & child : children) { nodes.push(child); } // draw the faces in back-to-front order while (!nodes.empty()) { Node* child = nodes.top(); nodes.pop(); const ColorCube & childsColorCube = ColorCube::getColorCube(child); //cerr << "before drawing colored box " << endl; childsColorCube.drawColoredBox(context, child->getWorldBB()); //cerr << "after drawing colored box" << endl; } context.getRenderingContext().popLighting(); context.getRenderingContext().popDepthBuffer(); context.getRenderingContext().popCullFace(); context.getRenderingContext().popBlending(); context.getRenderingContext().popMatrix_modelToCamera(); } context.getRenderingContext().popFBO(); colorTexture->downloadGLTexture(context.getRenderingContext()); // determine the color for each of the 6 faces for (uint8_t _side = 0; _side < 6; ++_side) { Geometry::side_t side = static_cast<Geometry::side_t> (_side); if (!prepareCamera(context, box, side)) continue; //calculate color from texture cc.colors[static_cast<uint8_t> (side)] = calculateColor(colorTexture.get(), camera->getViewport()); } } ColorCube::attachColorCube(node, cc); }
void MultiAlgoGroupNode::doDisplay(FrameContext & context, const RenderParam & rp) { context.displayNode(node.get(), rp); }