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; }
void ParticlePointRenderer::operator()(ParticleSystemNode* psys, FrameContext & context, const RenderParam & rp /* = 0 */) { if ( (rp.getFlag(NO_GEOMETRY)) ) return; // render particles std::vector<Particle> & particles = psys->getParticles(); uint32_t count = psys->getParticleCount(); Rendering::VertexDescription vertexDesc; const Rendering::VertexAttribute & posAttrib = vertexDesc.appendPosition3D(); const Rendering::VertexAttribute & colorAttrib = vertexDesc.appendColorRGBAByte(); // 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, count, count); mesh->setDataStrategy(Rendering::SimpleMeshDataStrategy::getPureLocalStrategy()); mesh->setDrawMode(Rendering::Mesh::DRAW_POINTS); // mesh->setUseIndexData(false); 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()); uint32_t * indices = indexData.data(); for(uint_fast32_t index = 0; index < count; ++index) { const Particle & p = particles[index]; colorAccessor->setColor(index, p.color); positionAccessor->setPosition(index, p.position); *indices++ = index; } indexData.markAsChanged(); indexData.updateIndexRange(); vertexData.markAsChanged(); vertexData.updateBoundingBox(); context.displayMesh(mesh.get()); }
State::stateResult_t VisibilitySubdivisionRenderer::doEnableState( FrameContext & context, Node *, const RenderParam & rp) { if (rp.getFlag(SKIP_RENDERER)) { return State::STATE_SKIPPED; } if (viSu == nullptr) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } // [AccumRendering] if(accumRenderingEnabled){ // camera moved? -> start new frame const Geometry::Matrix4x4 & newCamMat=context.getCamera()->getWorldTransformationMatrix(); if(newCamMat!=lastCamMatrix){ lastCamMatrix = newCamMat; startRuntime=0; } }else{ startRuntime=0; } // ---- uint32_t renderedTriangles = 0; if (hold) { for (const auto & object : holdObjects) { if (debugOutput) { debugDisplay(renderedTriangles, object, context, rp); } else { context.displayNode(object, rp); } } return State::STATE_SKIP_RENDERING; } Geometry::Vec3 pos = context.getCamera()->getWorldOrigin(); bool refreshCache = false; // Check if cached cell can be used. if (currentCell == nullptr || !currentCell->getBB().contains(pos)) { currentCell = viSu->getNodeAtPosition(pos); refreshCache = true; } if (currentCell == nullptr || !currentCell->isLeaf()) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } if (refreshCache) { try { const auto & vv = getVV(currentCell); const uint32_t maxIndex = vv.getIndexCount(); objects.clear(); objects.reserve(maxIndex); for(uint_fast32_t index = 0; index < maxIndex; ++index) { if(vv.getBenefits(index) == 0) { continue; } const VisibilityVector::costs_t costs = vv.getCosts(index); const VisibilityVector::benefits_t benefits = vv.getBenefits(index); const float score = static_cast<float>(costs) / static_cast<float>(benefits); objects.emplace_back(score, vv.getNode(index)); } } catch(...) { // Invalid information. => Fall back to standard rendering. return State::STATE_SKIPPED; } if (displayTexturedDepthMeshes) { #ifdef MINSG_EXT_OUTOFCORE for (const auto & depthMesh : depthMeshes) { OutOfCore::getCacheManager().setUserPriority(depthMesh.get(), 0); } #endif /* MINSG_EXT_OUTOFCORE */ depthMeshes.clear(); depthMeshes.reserve(6); textures.clear(); textures.reserve(6); const std::string dmDirectionStrings[6] = { "-dir_x1_y0_z0", "-dir_x-1_y0_z0", "-dir_x0_y1_z0", "-dir_x0_y-1_z0", "-dir_x0_y0_z1", "-dir_x0_y0_z-1" }; for (auto & dmDirectionString : dmDirectionStrings) { Util::GenericAttribute * attrib = currentCell->getAttribute("DepthMesh" + dmDirectionString); if (attrib == nullptr) { continue; } Util::FileName dmMeshPath(attrib->toString()); Util::Reference<Rendering::Mesh> dmMesh; #ifdef MINSG_EXT_OUTOFCORE Util::GenericAttribute * bbAttrib = currentCell->getAttribute("DepthMesh" + dmDirectionString + "-bounds"); if (bbAttrib == nullptr) { WARN("Found depth mesh with no bounding box."); continue; } std::vector<float> bbValues = Util::StringUtils::toFloats(bbAttrib->toString()); FAIL_IF(bbValues.size() != 6); const Geometry::Box meshBB(Geometry::Vec3(bbValues[0], bbValues[1], bbValues[2]), bbValues[3], bbValues[4], bbValues[5]); dmMesh = OutOfCore::addMesh(dmMeshPath, meshBB); #else /* MINSG_EXT_OUTOFCORE */ dmMesh = Rendering::Serialization::loadMesh(dmMeshPath); #endif /* MINSG_EXT_OUTOFCORE */ depthMeshes.emplace_back(dmMesh); // Count the depth mesh here already. renderedTriangles += dmMesh->getPrimitiveCount(); Util::GenericAttribute * texAttrib = currentCell->getAttribute("Texture" + dmDirectionString); if (texAttrib == nullptr) { continue; } Util::FileName texturePath(texAttrib->toString()); Util::Reference<Rendering::Texture> texture = Rendering::Serialization::loadTexture(texturePath); if (texture.isNull()) { WARN("Loading texture for depth mesh failed."); continue; } textures.emplace_back(texture); } } } const Geometry::Frustum & frustum = context.getCamera()->getFrustum(); holdObjects.clear(); holdObjects.reserve(objects.size()); std::sort(objects.begin(), objects.end()); for(const auto & ratioObjectPair : objects) { object_ptr o = ratioObjectPair.second; #ifdef MINSG_EXT_OUTOFCORE OutOfCore::getCacheManager().setUserPriority(o->getMesh(), 5); #endif /* MINSG_EXT_OUTOFCORE */ if (conditionalFrustumTest(frustum, o->getWorldBB(), rp)) { // [AccumRendering] // skip geometry rendered in the last frame if(renderedTriangles<startRuntime){ renderedTriangles += o->getTriangleCount(); continue; } // ---- if (debugOutput) { debugDisplay(renderedTriangles, o, context, rp); } else { context.displayNode(o, rp); renderedTriangles += o->getTriangleCount(); } holdObjects.push_back(o); } if (maxRuntime != 0 && renderedTriangles >= startRuntime+maxRuntime) { break; } } // Draw the textured depth meshes at the end. if (displayTexturedDepthMeshes) { context.getRenderingContext().pushAndSetPolygonOffset(Rendering::PolygonOffsetParameters(polygonOffsetFactor, polygonOffsetUnits)); auto texIt = textures.cbegin(); for (const auto & depthMesh : depthMeshes) { context.getRenderingContext().pushAndSetShader(getTDMShader()); context.getRenderingContext().pushAndSetTexture(0,texIt->get()); if (conditionalFrustumTest(frustum, depthMesh->getBoundingBox(), rp)) { context.displayMesh(depthMesh.get()); } context.getRenderingContext().popTexture(0); context.getRenderingContext().popShader(); #ifdef MINSG_EXT_OUTOFCORE OutOfCore::getCacheManager().setUserPriority(depthMesh.get(), 2); #endif /* MINSG_EXT_OUTOFCORE */ ++texIt; } context.getRenderingContext().popPolygonOffset(); } // [AccumRendering] startRuntime=renderedTriangles; // ---- return State::STATE_SKIP_RENDERING; }
State::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; }
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()); }