/**
 * ---|> [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]
void ShaderUniformState::doDisableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	Rendering::Shader * shader = context.getRenderingContext().getActiveShader();
	if(shader!=nullptr){
		for(const auto & uniform : priorValueStack.top()) {
			shader->setUniform(context.getRenderingContext(), uniform, true); // warn if unused--> should not happen
		}
	}
	priorValueStack.pop();
}
void ColorCubeGenerator::generateColorCubes(FrameContext& context, Node * node, uint32_t nodeCount, uint32_t triangleCount){
	if(fbo.isNull()){
		// init the data needed for processing the colors and process the color cubes
		depthTexture = Rendering::TextureUtils::createDepthTexture(maxTexSize * 6, maxTexSize);
		colorTexture = Rendering::TextureUtils::createStdTexture(maxTexSize * 6, maxTexSize, true);
		fbo = new Rendering::FBO();
		context.getRenderingContext().pushAndSetFBO(fbo.get());
		fbo->attachColorTexture(context.getRenderingContext(),colorTexture.get());
		fbo->attachDepthTexture(context.getRenderingContext(),depthTexture.get());
		context.getRenderingContext().popFBO();
		camera = new CameraNodeOrtho();
	}

	processColorCubes(context, node, nodeCount, triangleCount);
}
Beispiel #4
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;
}
Beispiel #5
0
State::stateResult_t OccludeeRenderer::doEnableState(FrameContext & context, Node * rootNode, const RenderParam & rp) {
	if (rp.getFlag(SKIP_RENDERER)) {
		return State::STATE_SKIPPED;
	}

	static PolygonModeState polygonMode;
	polygonMode.changeParameters().setMode(Rendering::PolygonModeParameters::LINE);

	occlusionCullingRenderer->setMode(OccRenderer::MODE_CULLING);
	const State::stateResult_t resultCulling = occlusionCullingRenderer->enableState(context, rootNode, rp);
	if(resultCulling != State::STATE_SKIP_RENDERING) {
		WARN("Using the OccRenderer for culling failed.");
		return resultCulling;
	}

	// Clear the depth buffer to be able to render the occluded geometry in front of the previously rendered geometry.
	context.getRenderingContext().clearDepth(1.0f);

	// Activate wireframe mode.
	polygonMode.enableState(context, rootNode, rp);

	occlusionCullingRenderer->setMode(OccRenderer::MODE_SHOW_CULLED);
	RenderParam rpWorldMatrix = rp;
	rpWorldMatrix.setFlag(USE_WORLD_MATRIX);
	const State::stateResult_t resultShowCulled = occlusionCullingRenderer->enableState(context, rootNode, rpWorldMatrix);
	if(resultShowCulled != State::STATE_SKIP_RENDERING) {
		WARN("Using the OccRenderer for showing the culled geometry failed.");
		return resultShowCulled;
	}

	// Deactivate wireframe mode.
	polygonMode.disableState(context, rootNode, rp);

	return State::STATE_SKIP_RENDERING;
}
//! ---|> [State]
State::stateResult_t ShaderUniformState::doEnableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	priorValueStack.push( std::vector<Rendering::Uniform>() );

	Rendering::Shader * shader = context.getRenderingContext().getActiveShader();

	if(shader!=nullptr){
		// assure that possible changes in the renderingContext are applied to the sg-uniforms before querying the uniforms
		context.getRenderingContext().applyChanges();

		for(const auto & uniformEntry : uMap) {
			const Rendering::Uniform & uniform(uniformEntry.second);
			const Rendering::Uniform & priorUniform(shader->getUniform(uniform.getNameId()));
			if(priorUniform.isNull())
				continue;
			priorValueStack.top().push_back(priorUniform);
			shader->setUniform(context.getRenderingContext(),uniform,true); // warn if unused--> should not happen
		}
	}
	return State::STATE_OK;
}
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();
}
Beispiel #8
0
//! ---|> [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;
}
Beispiel #9
0
//! ---|> [State]
State::stateResult_t ShaderState::doEnableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	if( !shader )
		return State::STATE_SKIPPED;

	auto & rCtxt = context.getRenderingContext();

	// push current shader to stack
	rCtxt.pushAndSetShader(shader.get());
	
	if( !rCtxt.isShaderEnabled(shader.get()) ){
		rCtxt.popShader();
		deactivate();
		WARN("Enabling ShaderState failed. State has been deactivated!");
		return State::STATE_SKIPPED;
	}
	
	for(const auto & uniformEntry : uMap) 
		shader->setUniform(rCtxt, uniformEntry.second);
	return State::STATE_OK;
}
//! 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);
	}
}
Beispiel #11
0
//! ---|> [State]
void ShaderState::doDisableState(FrameContext & context, Node *, const RenderParam & /*rp*/) {
	// restore old shader
	context.getRenderingContext().popShader();
}
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;
}
Beispiel #13
0
State::stateResult_t PhotonRenderer::doEnableState(FrameContext & context, Node * node, const RenderParam & rp){
#ifdef MINSG_THESISSTANISLAW_GATHER_STATISTICS
  Rendering::RenderingContext::finish();
  _timer.reset();
#endif // MINSG_THESISSTANISLAW_GATHER_STATISTICS

  if(!_photonSampler){
    WARN("No PhotonSampler present in PhotonRenderer!");
    return State::stateResult_t::STATE_SKIPPED;
  }
  
  if(!_approxScene){
    WARN("No approximated Scene present in PhotonRenderer!");
    return State::stateResult_t::STATE_SKIPPED;
  }
  
  
  auto& rc = context.getRenderingContext();
  rc.setImmediateMode(true);
  rc.applyChanges();
  
  if(_fboChanged){
    if(!initializeFBO(rc)){
      WARN("Could not initialize FBO for PhotonRenderer!");
      return State::stateResult_t::STATE_SKIPPED;
    }
    _fboChanged = false;
  }
  
  RenderParam newRp;
  
  rc.pushAndSetFBO(_fbo.get());
  rc.clearDepth(1.0f);
  
  rc.applyChanges();
  
  for(int32_t i = 0; i < _photonSampler->getPhotonNumber(); i++){
    _fbo->setDrawBuffers(2);
    rc.pushAndSetShader(_indirectLightShader.get());
    _lightPatchRenderer->bindTBO(rc, true, false);
    _photonSampler->bindPhotonBuffer(1);
    context.pushAndSetCamera(_photonCamera.get());
    _indirectLightShader->setUniform(rc, Rendering::Uniform("photonID", i));
    
    rc.clearDepth(1.0f);
    rc.clearColor(Util::Color4f(0.f, 0.f, 0.f, 0.f));
    _approxScene->display(context, newRp);
    
    context.popCamera();
    _photonSampler->unbindPhotonBuffer(1);
    _lightPatchRenderer->unbindTBO(rc);
    rc.popShader();
    
    
    // Accumulate all pixel values in one photon 
    _fbo->setDrawBuffers(0);
    rc.pushAndSetShader(_accumulationShader.get());
    _accumulationShader->setUniform(rc, Rendering::Uniform("photonID", i));
    _accumulationShader->setUniform(rc, Rendering::Uniform("samplingWidth", static_cast<int>(_samplingWidth)));
    _accumulationShader->setUniform(rc, Rendering::Uniform("samplingHeight", static_cast<int>(_samplingHeight)));
    _photonSampler->bindPhotonBuffer(1);
    rc.clearDepth(1.0f);
    Rendering::TextureUtils::drawTextureToScreen(rc, Geometry::Rect_i(0, 0, _samplingWidth, _samplingHeight), *_indirectLightTexture.get(), Geometry::Rect_f(0.0f, 0.0f, 1.0f, 1.0f));
    _photonSampler->unbindPhotonBuffer(1);
    rc.popShader();
  }
  
  rc.popFBO();
  
  rc.setImmediateMode(false);
  
//  rc.pushAndSetShader(nullptr);
//  Rendering::TextureUtils::drawTextureToScreen(rc, Geometry::Rect_i(0, 0, _samplingWidth, _samplingHeight), *(_indirectLightTexture.get()), Geometry::Rect_f(0.0f, 0.0f, 1.0f, 1.0f));
//  rc.popShader();
//  return State::stateResult_t::STATE_SKIP_RENDERING;

#ifdef MINSG_THESISSTANISLAW_GATHER_STATISTICS
  Rendering::RenderingContext::finish();
  _timer.stop();
  auto& stats = context.getStatistics();
  Statistics::instance(stats).addPhotonRendererTime(stats, _timer.getMilliseconds());
#endif // MINSG_THESISSTANISLAW_GATHER_STATISTICS

  return State::stateResult_t::STATE_OK;
}
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);
}
//! ---|> 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()));
		}

	}
}
Beispiel #16
0
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;
}
Beispiel #17
0
//! ---|> 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;
}
Beispiel #18
0
void ShaderState::setUniform(FrameContext & context, const Rendering::Uniform & value) {
	setUniform(value);
	shader->setUniform(context.getRenderingContext(),value,true,true); // warn if uniform is not defined in shader and force at least one try on applying the uniform
}
Beispiel #19
0
//! ---|> [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;
}
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;
}
//! 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);
		}
	}
}
Beispiel #22
0
//! (internal) Main culling method
State::stateResult_t OccRenderer::performCulling(FrameContext & context,Node * rootNode, const RenderParam & rp){
	if(mode==MODE_UNCONDITIONED){ // destroy temporal coherence
		frameNumber++;
	}
	frameNumber++;

	updateNodeInformation(context,rootNode); // ???

	// used for statistics
	unsigned int tests=0;
	int testsVisible=0;
	int testsInvisible=0;
	int occludedGeometryNodes=0;


	Statistics & statistics = context.getStatistics();

	RenderParam childParam = rp + USE_WORLD_MATRIX;

	const Geometry::Vec3 camPos=context.getCamera()->getWorldOrigin();


//	NodeDistancePriorityQueue_F2B distanceQueue(camPos);
	NodeDistancePriorityQueue_F2B distanceQueue(camPos);

	{	// add root node's children
		const auto children = getChildNodes(rootNode);
		for(auto & child : children) {
			distanceQueue.push(child);
		}
	}

	std::queue<std::pair<Rendering::OcclusionQuery, Node *>> queryQueue;

//    bool wasIdle=true;
	int idleCount=0;
	while ( (!distanceQueue.empty()) || (!queryQueue.empty() ) ) {
		bool idle=true;

		while ( !queryQueue.empty() && queryQueue.front().first.isResultAvailable() ) {
			idle=false;

			const OcclusionQuery & currentQuery = queryQueue.front().first;
			unsigned int result = currentQuery.getResult();
			Node * node = queryQueue.front().second;

			queryQueue.pop();
			NodeInfo * nodeInfo = getNodeInfo(node);

			// Node is visible?
			if (result>0 ) {

				statistics.pushEvent(Statistics::EVENT_TYPE_END_TEST_VISIBLE,nodeInfo->getActualSubtreeComplexity());

				testsVisible++;
				if (node->isClosed()) {
					// mark parents as visible
					Node * n=node;
					NodeInfo * ni=nodeInfo;
					while( ni->getVisibleFrameNumber()!=frameNumber){
						ni->setVisibleFrameNumber(frameNumber);
						n=n->getParent();
						if(n==nullptr || n==rootNode) break;
						ni=getNodeInfo(n);
					}
				}
				nodeInfo->setVisibleFrameNumber(frameNumber);

				// haben wir schon bearbeitet? -> Weiter...
				if (nodeInfo->getProcessedFrameNumber()==frameNumber)
					continue;

////                if(node->visibleFrameNumber != (frameNumber-1)){ ????
				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);

////                }
			}// Node is fully occluded?
			else {
				testsInvisible++;


				statistics.pushEvent(Statistics::EVENT_TYPE_END_TEST_INVISIBLE, nodeInfo->getActualSubtreeComplexity());

				// not processed yet?
				if (nodeInfo->getProcessedFrameNumber()!=frameNumber) {
					// TODO: Store and propagate in tree.
					occludedGeometryNodes+=collectNodesInFrustum<GeometryNode>(node,context.getCamera()->getFrustum()).size();

					// mark the node as processed
					nodeInfo->setProcessedFrameNumber(frameNumber);
				}
				// In diesem Frame verdeckt worden? (dann haben wir nicht mit der Bearbeitung gewartet und
				// die Kinder liegen bereits in der distanceQueue; die sollten jetzt �bersprungen werden)
				if ( nodeInfo->getVisibleFrameNumber() == (frameNumber-1) ) {
					if (!node->isClosed()) {
						const auto children = getChildNodes(node);
						for(auto & child : children) {
							getNodeInfo(child)->setProcessedFrameNumber(frameNumber);
							// TODO: Check if ancestors have to be removed too.
						}
					}
				}
			}
		}
		// ...
		if ( ! distanceQueue.empty()) {

			idle=false;

			Node * node=distanceQueue.top();
			NodeInfo * nodeInfo=getNodeInfo(node);
			distanceQueue.pop();

			// If the current node has already been processed, then continue.
			if (nodeInfo->getProcessedFrameNumber()==frameNumber ) continue; // ||node->isEmpty()

//			// skip empty subtrees // does never happen (checked in processNode)
//			if( nodeInfo->getActualSubtreeComplexity() == 0){
//                nullBoxes++;
//                continue;
//			}

			// Kamera innerhalb der (um die nearplane vergroesserte) Box? -> immer sichtbar
			// [2008-01-04_CJ] Bugfix: added nearplane addition; could result in dissapearing scene-parts.
			Geometry::Box extendedBox=node->getWorldBB(); //node->getGeometryBB();
			extendedBox.resizeAbs(context.getCamera()->getNearPlane());
			if (extendedBox.contains(camPos)) {

				nodeInfo->setVisibleFrameNumber(frameNumber);

				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);
				continue;
			}

			// !IS_INSIDE_FRUSTUM(node)
			if ( nodeInfo->getActualFrustumStatus()== Geometry::Frustum::OUTSIDE)
				continue;

			// [MODE_OPT_CULLING] For optimal culling, skip all unnecessary tests
			if(mode==MODE_OPT_CULLING && nodeInfo->getVisibleFrameNumber() == (frameNumber-1)){
				nodeInfo->setVisibleFrameNumber(frameNumber);
				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);
				continue;
			}

			// if query reasonable
			// TODO: Something missing here?

			{ // start occlusion test for the current node
				Rendering::OcclusionQuery query;

				Rendering::OcclusionQuery::enableTestMode(context.getRenderingContext());
				query.begin();
				Rendering::drawFastAbsBox(context.getRenderingContext(), node->getWorldBB());
				query.end();
				Rendering::OcclusionQuery::disableTestMode(context.getRenderingContext());
				tests++;
				queryQueue.emplace(std::move(query), node);

				statistics.pushEvent(Statistics::EVENT_TYPE_START_TEST, nodeInfo->getActualSubtreeComplexity());
			}

			// if the current node was visible in the last frame,
			//  then assume that it is also visible in this frame and process it.
			if (nodeInfo->getVisibleFrameNumber() == (frameNumber-1) ) {
				// Process node
				processNode(context,node,nodeInfo,distanceQueue,childParam);
			}

		}
//		else{
			// waiting

//		}
		if (idle) {
			statistics.pushEvent(Statistics::EVENT_TYPE_IDLE, idleCount++);
		} else {
			idleCount = 0;
		}

	}

	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestCounter(), tests);
	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestVisibleCounter(), testsVisible);
	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getOccTestInvisibleCounter(), testsInvisible);
	statistics.addValue(OcclusionCullingStatistics::instance(statistics).getCulledGeometryNodeCounter(), occludedGeometryNodes);
	statistics.pushEvent(Statistics::EVENT_TYPE_FRAME_END,0.3);

	return State::STATE_SKIP_RENDERING;
}
//! 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;
	}
}
/*! @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 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()));
	}
}
Beispiel #26
0
void ParticleBillboardRenderer::operator()(ParticleSystemNode * psys, FrameContext & context, const RenderParam & rp) {
	if(rp.getFlag(NO_GEOMETRY)) {
		return;
	}

	const auto & worldToCamera = context.getRenderingContext().getMatrix_worldToCamera();
	const auto cameraToWorld = worldToCamera.inverse();

	const auto halfRight = cameraToWorld.transformDirection(context.getWorldRightVector() * 0.5f);
	const auto halfUp = cameraToWorld.transformDirection(context.getWorldUpVector() * 0.5f);

	// 2. just update position for each particle and render
	// render particles
	const uint32_t count = psys->getParticleCount();

	Rendering::VertexDescription vertexDesc;
	const Rendering::VertexAttribute & posAttrib = vertexDesc.appendPosition3D();
	const Rendering::VertexAttribute & colorAttrib = vertexDesc.appendColorRGBAByte();
	const Rendering::VertexAttribute & texCoordAttrib = vertexDesc.appendTexCoord();
	// The usage of a cache for the mesh has been tested. Reusing a preallocated mesh is not faster.
	Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, 4 * count, 6 * count);
	mesh->setDataStrategy(Rendering::SimpleMeshDataStrategy::getPureLocalStrategy());
	Rendering::MeshIndexData & indexData = mesh->openIndexData();
	Rendering::MeshVertexData & vertexData = mesh->openVertexData();
	Util::Reference<Rendering::PositionAttributeAccessor> positionAccessor = Rendering::PositionAttributeAccessor::create(vertexData, posAttrib.getNameId());
	Util::Reference<Rendering::ColorAttributeAccessor> colorAccessor = Rendering::ColorAttributeAccessor::create(vertexData, colorAttrib.getNameId());
	Util::Reference<Rendering::TexCoordAttributeAccessor> texCoordAccessor = Rendering::TexCoordAttributeAccessor::create(vertexData, texCoordAttrib.getNameId());
	uint32_t * indices = indexData.data();

	uint_fast32_t index = 0;
	for(const auto & p : psys->getParticles()) {
		const Geometry::Vec3f upOffset = halfUp * p.size.getHeight();
		const Geometry::Vec3f rightOffset = halfRight * p.size.getWidth();

		colorAccessor->setColor(index + 0, p.color);
		texCoordAccessor->setCoordinate(index + 0, Geometry::Vec2f(0.0f, 0.0f));
		positionAccessor->setPosition(index + 0, p.position + upOffset - rightOffset);

		colorAccessor->setColor(index + 1, p.color);
		texCoordAccessor->setCoordinate(index + 1, Geometry::Vec2f(0.0f, 1.0f));
		positionAccessor->setPosition(index + 1, p.position - upOffset - rightOffset);

		colorAccessor->setColor(index + 2, p.color);
		texCoordAccessor->setCoordinate(index + 2, Geometry::Vec2f(1.0f, 1.0f));
		positionAccessor->setPosition(index + 2, p.position - upOffset + rightOffset);

		colorAccessor->setColor(index + 3, p.color);
		texCoordAccessor->setCoordinate(index + 3, Geometry::Vec2f(1.0f, 0.0f));
		positionAccessor->setPosition(index + 3, p.position + upOffset + rightOffset);

		*indices++ = index + 0;
		*indices++ = index + 1;
		*indices++ = index + 3;

		*indices++ = index + 1;
		*indices++ = index + 2;
		*indices++ = index + 3;

		index += 4;
	}

	indexData.markAsChanged();
	indexData.updateIndexRange();
	vertexData.markAsChanged();
	vertexData.updateBoundingBox();
	context.displayMesh(mesh.get());
}