NodeRendererResult SurfelRenderer::displayNode(FrameContext & context, Node * node, const RenderParam & /*rp*/){ static const Util::StringIdentifier SURFEL_ATTRIBUTE("surfels"); auto surfelAttribute = dynamic_cast<Util::ReferenceAttribute<Rendering::Mesh>*>(node->findAttribute( SURFEL_ATTRIBUTE )); if( !surfelAttribute || !surfelAttribute->get()) return NodeRendererResult::PASS_ON; Rendering::Mesh& surfelMesh = *surfelAttribute->get(); const Geometry::Rect projection = context.getProjectedRect(node); const float approxProjectedSideLength = std::sqrt(projection.getHeight() * projection.getWidth()); // const auto& worldBB = node->getWorldBB(); // const float approxProjectedSideLength = projectionScale * worldBB.getDiameter() / (worldBB.getCenter()-cameraOrigin).length(); if(approxProjectedSideLength > maxSideLength) return NodeRendererResult::PASS_ON; static const Util::StringIdentifier REL_COVERING_ATTRIBUTE("surfelRelCovering"); auto surfelCoverageAttr = node->findAttribute(REL_COVERING_ATTRIBUTE); const float relCovering = surfelCoverageAttr ? surfelCoverageAttr->toFloat() : 0.5; const float approxProjectedArea = approxProjectedSideLength * approxProjectedSideLength * relCovering; uint32_t surfelCount = std::min( surfelMesh.isUsingIndexData() ? surfelMesh.getIndexCount() : surfelMesh.getVertexCount(), static_cast<uint32_t>(approxProjectedArea * countFactor) + 1); float surfelSize = std::min(sizeFactor * approxProjectedArea / surfelCount,maxSurfelSize); bool handled = true; if(approxProjectedSideLength > minSideLength && minSideLength<maxSideLength){ const float f = 1.0f -(approxProjectedSideLength-minSideLength) / (maxSideLength-minSideLength); surfelCount = std::min( surfelMesh.isUsingIndexData() ? surfelMesh.getIndexCount() : surfelMesh.getVertexCount(), static_cast<uint32_t>(f * surfelCount) + 1); surfelSize *= f; handled = false; // std::cout << approxProjectedSideLength<<"\t"<<f<<"\n"; } // std::cout << surfelSize<<"\t"<<"\n"; // if( node->getRenderingLayers()&0x02 ) // std::cout << "pSize"<<approxProjectedSideLength << "\t#:"<<surfelCount<<"\ts:"<<surfelSize<<"\n"; auto& renderingContext = context.getRenderingContext(); static Rendering::Uniform enableSurfels("renderSurfels", true); static Rendering::Uniform disableSurfels("renderSurfels", false); renderingContext.setGlobalUniform(enableSurfels); renderingContext.pushAndSetPointParameters( Rendering::PointParameters(std::min(surfelSize,32.0f) )); renderingContext.pushAndSetMatrix_modelToCamera( renderingContext.getMatrix_worldToCamera() ); renderingContext.multMatrix_modelToCamera(node->getWorldTransformationMatrix()); context.displayMesh(&surfelMesh, 0, surfelCount ); renderingContext.popMatrix_modelToCamera(); renderingContext.popPointParameters(); renderingContext.setGlobalUniform(disableSurfels); return handled ? NodeRendererResult::NODE_HANDLED : NodeRendererResult::PASS_ON; }
//! Distribute the budget based on the projected size of the child nodes. static void distributeProjectedSize(double value, const Util::StringIdentifier & attributeId, Node * node, FrameContext & context) { const auto children = getChildNodes(node); // A pair stores a node and its projected size. std::vector<std::pair<Node *, float>> nodeProjSizePairs; nodeProjSizePairs.reserve(children.size()); double projSizeSum = 0.0; const Geometry::Rect_f screenRect(context.getRenderingContext().getWindowClientArea()); for(const auto & child : children) { // Clip the projected rect to the screen. auto projRect = context.getProjectedRect(child); projRect.clipBy(screenRect); const auto projSize = projRect.getArea(); projSizeSum += projSize; nodeProjSizePairs.emplace_back(child, projSize); } for(const auto & nodeProjSizePair : nodeProjSizePairs) { const double factor = nodeProjSizePair.second / projSizeSum; setOrUpdateAttribute(nodeProjSizePair.first, attributeId, factor * value); } }
//! Distribute the budget based on the projected size and the primitive count of the child nodes. static void distributeProjectedSizeAndPrimitiveCount(double value, const Util::StringIdentifier & attributeId, Node * node, FrameContext & context) { static const Util::StringIdentifier primitiveCountId("PrimitiveCount"); struct PrimitiveCountAnnotationVisitor : public NodeVisitor { const Util::StringIdentifier & m_primitiveCountId; PrimitiveCountAnnotationVisitor(const Util::StringIdentifier & p_primitiveCountId) : m_primitiveCountId(p_primitiveCountId) { } virtual ~PrimitiveCountAnnotationVisitor() { } NodeVisitor::status leave(Node * _node) override { auto geoNode = dynamic_cast<GeometryNode *>(_node); uint32_t primitiveCount = 0; if(geoNode != nullptr) { const auto mesh = geoNode->getMesh(); primitiveCount = mesh == nullptr ? 0 : mesh->getPrimitiveCount(); } else { const auto children = getChildNodes(_node); for(const auto & child : children) { primitiveCount += child->getAttribute(m_primitiveCountId)->toUnsignedInt(); } } _node->setAttribute(m_primitiveCountId, Util::GenericAttribute::createNumber(primitiveCount)); return CONTINUE_TRAVERSAL; } }; const auto children = getChildNodes(node); // A tuple stores the primitive count, the node and its projected size. std::vector<std::tuple<uint32_t, Node *, float>> primitiveCountNodeProjSizeTuples; primitiveCountNodeProjSizeTuples.reserve(children.size()); double projSizeSum = 0.0; const Geometry::Rect_f screenRect(context.getRenderingContext().getWindowClientArea()); for(const auto & child : children) { if(!child->isAttributeSet(primitiveCountId)) { PrimitiveCountAnnotationVisitor visitor(primitiveCountId); child->traverse(visitor); } const auto primitiveCount = child->getAttribute(primitiveCountId)->toUnsignedInt(); // Clip the projected rect to the screen. auto projRect = context.getProjectedRect(child); projRect.clipBy(screenRect); const auto projSize = projRect.getArea(); projSizeSum += projSize; primitiveCountNodeProjSizeTuples.emplace_back(primitiveCount, child, projSize); } // Begin with the node with the lowest primitive count std::sort(primitiveCountNodeProjSizeTuples.begin(), primitiveCountNodeProjSizeTuples.end()); for(const auto & primitiveCountNodeProjSizeTuple : primitiveCountNodeProjSizeTuples) { const auto primitiveCount = std::get<0>(primitiveCountNodeProjSizeTuple); const auto projSize = std::get<2>(primitiveCountNodeProjSizeTuple); const auto projSizeFactor = projSize / projSizeSum; const auto primitiveAssignment = std::min(static_cast<uint32_t>(projSizeFactor * value), primitiveCount); setOrUpdateAttribute(std::get<1>(primitiveCountNodeProjSizeTuple), attributeId, primitiveAssignment); value -= primitiveAssignment; projSizeSum -= projSize; } }
//! Distribute the budget based on the projected size and the primitive count of the child nodes in an iterative manner for correct distribution. static void distributeProjectedSizeAndPrimitiveCountIterative(double value, const Util::StringIdentifier & attributeId, Node * node, FrameContext & context) { static const Util::StringIdentifier primitiveCountId("PrimitiveCount"); struct PrimitiveCountAnnotationVisitor : public NodeVisitor { const Util::StringIdentifier & m_primitiveCountId; PrimitiveCountAnnotationVisitor(const Util::StringIdentifier & p_primitiveCountId) : m_primitiveCountId(p_primitiveCountId) { } virtual ~PrimitiveCountAnnotationVisitor() { } NodeVisitor::status leave(Node * _node) override { auto geoNode = dynamic_cast<GeometryNode *>(_node); uint32_t primitiveCount = 0; if(geoNode != nullptr) { const auto mesh = geoNode->getMesh(); primitiveCount = mesh == nullptr ? 0 : mesh->getPrimitiveCount(); } else { const auto children = getChildNodes(_node); for(const auto & child : children) { primitiveCount += child->getAttribute(m_primitiveCountId)->toUnsignedInt(); } } _node->setAttribute(m_primitiveCountId, Util::GenericAttribute::createNumber(primitiveCount)); return CONTINUE_TRAVERSAL; } }; const auto children = getChildNodes(node); // A pair stores the primitive count, the node and its projected size. std::deque<std::tuple<uint32_t, Node *, float>> primitiveCountNodeProjSizeTuples; double projSizeSum = 0.0; const Geometry::Rect_f screenRect(context.getRenderingContext().getWindowClientArea()); for(const auto & child : children) { if(!child->isAttributeSet(primitiveCountId)) { PrimitiveCountAnnotationVisitor visitor(primitiveCountId); child->traverse(visitor); } const auto primitiveCount = child->getAttribute(primitiveCountId)->toUnsignedInt(); // Clip the projected rect to the screen. auto projRect = context.getProjectedRect(child); projRect.clipBy(screenRect); const auto projSize = projRect.getArea(); projSizeSum += projSize; primitiveCountNodeProjSizeTuples.emplace_back(primitiveCount, child, projSize); } // Begin with the node with the lowest primitive count std::sort(primitiveCountNodeProjSizeTuples.begin(), primitiveCountNodeProjSizeTuples.end()); /* Distribute budget until one node gets all budget it asked for. * This means the previous distributions would receive more budget, * thus remove that node from distribution (update value and projSizeSum) * and start again. */ std::deque<std::tuple<uint32_t, Node *, float>> tmpDeque(primitiveCountNodeProjSizeTuples); // TODO: fails to copy values correctly!!! bool nodeRemoved; double tmpValue; double tmpProjSizeSum; double remainingProjSizeSum = projSizeSum; do{ nodeRemoved = false; tmpValue = value; tmpProjSizeSum = remainingProjSizeSum; for(auto it=tmpDeque.begin(); it!=tmpDeque.end(); ++it) { std::tuple<uint32_t, Node *, float> element = *it; const auto primitiveCount = std::get<0>(element); const auto projSize = std::get<2>(element); const auto projSizeFactor = projSize / tmpProjSizeSum; const auto primitiveAssignment = std::min(static_cast<uint32_t>(projSizeFactor * tmpValue), primitiveCount); setOrUpdateAttribute(std::get<1>(element), attributeId, primitiveAssignment); if(primitiveAssignment == primitiveCount){ nodeRemoved = true; tmpDeque.erase(it); value -= primitiveCount; remainingProjSizeSum -= projSize; break; } tmpValue -= primitiveAssignment; tmpProjSizeSum -= projSize; } }while(nodeRemoved); // distribute remaining part of value based on projected size only if(tmpValue >= 1){ for(const auto & primitiveCountNodeProjSizeTuple : primitiveCountNodeProjSizeTuples) { const auto projSize = std::get<2>(primitiveCountNodeProjSizeTuple); const auto projSizeFactor = projSize / projSizeSum; const auto attribute = dynamic_cast<Util::_NumberAttribute<double> *>(std::get<1>(primitiveCountNodeProjSizeTuple)->getAttribute(attributeId)); attribute->set(attribute->get() + projSizeFactor * tmpValue); } } }