Esempio n. 1
0
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);
		}
	}
}