From f5d68cbd5e12fe24da3c6a24c1b1386762bd691a Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 19 Apr 2024 17:48:28 +0200 Subject: [PATCH] Issue/3070 - Outline/border to textured points (#3191) * Add option for outline styles (round, square, bottom) * Apply color map to point borders --- .../pointcloud/renderablepointcloud.cpp | 78 ++++++++++++++++--- .../pointcloud/renderablepointcloud.h | 4 +- .../shaders/pointcloud/pointcloud_fs.glsl | 48 ++++++++++-- 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.cpp b/modules/base/rendering/pointcloud/renderablepointcloud.cpp index 861b2edb4e..96df080718 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.cpp +++ b/modules/base/rendering/pointcloud/renderablepointcloud.cpp @@ -58,7 +58,7 @@ namespace { constexpr std::string_view _loggerCat = "RenderablePointCloud"; - constexpr std::array UniformNames = { + constexpr std::array UniformNames = { "cameraViewMatrix", "projectionMatrix", "modelMatrix", "cameraPosition", "cameraLookUp", "renderOption", "maxAngularSize", "color", "opacity", "scaleExponent", "scaleFactor", "up", "right", "fadeInValue", "hasSpriteTexture", @@ -66,7 +66,8 @@ namespace { "nanColor", "useNanColor", "hideOutsideRange", "enableMaxSizeControl", "aboveRangeColor", "useAboveRangeColor", "belowRangeColor", "useBelowRangeColor", "hasDvarScaling", "dvarScaleFactor", "enableOutline", "outlineColor", - "outlineWeight", "aspectRatioScale", "useOrientationData" + "outlineWeight", "outlineStyle", "useCmapOutline", "aspectRatioScale", + "useOrientationData" }; enum RenderOption { @@ -75,6 +76,12 @@ namespace { FixedRotation }; + enum OutlineStyle { + Round = 0, + Square, + Bottom + }; + constexpr openspace::properties::Property::PropertyInfo TextureEnabledInfo = { "Enabled", "Enabled", @@ -318,6 +325,23 @@ namespace { openspace::properties::Property::Visibility::AdvancedUser }; + constexpr openspace::properties::Property::PropertyInfo OutlineStyleInfo = { + "OutlineStyle", + "Outline Style", + "This setting decides the shape of points that have an outline (round, square, " + "or lust a line at the bottom). Note that anything but \"Round\" will lead to " + "the point being drawed as squares.", + openspace::properties::Property::Visibility::AdvancedUser + }; + + constexpr openspace::properties::Property::PropertyInfo ApplyColorMapToOutlineInfo = { + "ApplyColorMapToOutline", + "Apply Color Map to Outline", + "If true and the outline is enabled, the color map will be applied to the " + "outline rather than the point body. Only works if color mapping is enabled.", + openspace::properties::Property::Visibility::AdvancedUser + }; + // A RenderablePointCloud can be used to render point-based datasets in 3D space, // optionally including color mapping, a sprite texture and labels. There are several // properties that affect the visuals of the points, such as settings for scaling, @@ -462,6 +486,17 @@ namespace { // [[codegen::verbatim(OutlineColorInfo.description)]] std::optional outlineWeight; + + enum class [[codegen::map(OutlineStyle)]] OutlineStyle { + Round, + Square, + Bottom + }; + // [[codegen::verbatim(OutlineStyleInfo.description)]] + std::optional outlineStyle; + + // [[codegen::verbatim(ApplyColorMapToOutlineInfo.description)]] + std::optional applyColorMapToOutline; }; // Settings related to the coloring of the points, such as a fixed color, // color map, etc. @@ -532,9 +567,29 @@ RenderablePointCloud::ColorSettings::ColorSettings(const ghoul::Dictionary& dict , enableOutline(EnableOutlineInfo, false) , outlineColor(OutlineColorInfo, glm::vec3(0.23f), glm::vec3(0.f), glm::vec3(1.f)) , outlineWeight(OutlineWeightInfo, 0.2f, 0.f, 1.f) + , outlineStyle(OutlineStyleInfo) + , applyCmapToOutline(ApplyColorMapToOutlineInfo, false) { const Parameters p = codegen::bake(dictionary); + pointColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(pointColor); + + addProperty(enableOutline); + + outlineColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(outlineColor); + + addProperty(outlineWeight); + + outlineStyle.addOption(OutlineStyle::Round, "Round"); + outlineStyle.addOption(OutlineStyle::Square, "Square"); + outlineStyle.addOption(OutlineStyle::Bottom, "Bottom"); + outlineStyle = OutlineStyle::Round; + addProperty(outlineStyle); + + addProperty(applyCmapToOutline); + const bool hasColoring = p.coloring.has_value(); if (hasColoring) { const Parameters::ColorSettings settings = *p.coloring; @@ -550,16 +605,15 @@ RenderablePointCloud::ColorSettings::ColorSettings(const ghoul::Dictionary& dict enableOutline = p.coloring->enableOutline.value_or(enableOutline); outlineColor = p.coloring->outlineColor.value_or(outlineColor); outlineWeight = p.coloring->outlineWeight.value_or(outlineWeight); + + if (p.coloring->outlineStyle.has_value()) { + outlineStyle = codegen::map(*p.coloring->outlineStyle); + } + + applyCmapToOutline = p.coloring->applyColorMapToOutline.value_or( + applyCmapToOutline + ); } - pointColor.setViewOption(properties::Property::ViewOptions::Color); - addProperty(pointColor); - - addProperty(enableOutline); - - outlineColor.setViewOption(properties::Property::ViewOptions::Color); - addProperty(outlineColor); - - addProperty(outlineWeight); } RenderablePointCloud::Texture::Texture() @@ -1211,6 +1265,8 @@ void RenderablePointCloud::renderPoints(const RenderData& data, _program->setUniform(_uniformCache.enableOutline, _colorSettings.enableOutline); _program->setUniform(_uniformCache.outlineColor, _colorSettings.outlineColor); _program->setUniform(_uniformCache.outlineWeight, _colorSettings.outlineWeight); + _program->setUniform(_uniformCache.outlineStyle, _colorSettings.outlineStyle); + _program->setUniform(_uniformCache.useCmapOutline, _colorSettings.applyCmapToOutline); bool useColorMap = hasColorData() && _colorSettings.colorMapping->enabled && _colorSettings.colorMapping->texture(); diff --git a/modules/base/rendering/pointcloud/renderablepointcloud.h b/modules/base/rendering/pointcloud/renderablepointcloud.h index 6051d66e67..d0aed60b73 100644 --- a/modules/base/rendering/pointcloud/renderablepointcloud.h +++ b/modules/base/rendering/pointcloud/renderablepointcloud.h @@ -190,6 +190,8 @@ protected: properties::BoolProperty enableOutline; properties::Vec3Property outlineColor; properties::FloatProperty outlineWeight; + properties::OptionProperty outlineStyle; + properties::BoolProperty applyCmapToOutline; }; ColorSettings _colorSettings; @@ -231,7 +233,7 @@ protected: cmapRangeMin, cmapRangeMax, nanColor, useNanColor, hideOutsideRange, enableMaxSizeControl, aboveRangeColor, useAboveRangeColor, belowRangeColor, useBelowRangeColor, hasDvarScaling, dvarScaleFactor, enableOutline, outlineColor, - outlineWeight, aspectRatioScale, useOrientationData + outlineWeight, outlineStyle, useCmapOutline, aspectRatioScale, useOrientationData ) _uniformCache; std::filesystem::path _dataFile; diff --git a/modules/base/shaders/pointcloud/pointcloud_fs.glsl b/modules/base/shaders/pointcloud/pointcloud_fs.glsl index ee160705f1..af975b08ab 100644 --- a/modules/base/shaders/pointcloud/pointcloud_fs.glsl +++ b/modules/base/shaders/pointcloud/pointcloud_fs.glsl @@ -56,6 +56,13 @@ uniform float outlineWeight; uniform float fadeInValue; +uniform bool useCmapOutline; +uniform int outlineStyle; + +const int OutlineStyleRound = 0; +const int OutlineStyleSquare = 1; +const int OutlineStyleBottom = 2; + vec4 sampleColorMap(float dataValue) { if (useNanColor && isnan(dataValue)) { return nanColor; @@ -85,21 +92,52 @@ Fragment getFragment() { } // Moving the origin to the center and calculating the length - float lengthFromCenter = length((texCoord - vec2(0.5)) * 2.0); - if (!hasSpriteTexture && (lengthFromCenter > 1.0)) { + vec2 centeredTexCoords = (texCoord - vec2(0.5)) * 2.0; + float lengthFromCenter = length(centeredTexCoords); + + bool shouldBeRound = (!hasSpriteTexture && !enableOutline) || + (enableOutline && outlineStyle == OutlineStyleRound); + + if (shouldBeRound && (lengthFromCenter > 1.0)) { discard; } vec4 fullColor = vec4(color, 1.0); + vec4 cmapColor = vec4(1.0); if (useColorMap) { - fullColor = sampleColorMap(gs_colorParameter); + cmapColor = sampleColorMap(gs_colorParameter); + if (!useCmapOutline) { + fullColor = cmapColor; + } } + vec4 textureColor = vec4(1.0); if (hasSpriteTexture) { fullColor *= texture(spriteTexture, vec3(texCoord, layer)); } - else if (enableOutline && (lengthFromCenter > (1.0 - outlineWeight))) { - fullColor.rgb = outlineColor; + + // Border + if (enableOutline) { + bool pixelIsOutline = false; + if (outlineStyle == OutlineStyleRound) { + pixelIsOutline = lengthFromCenter > (1.0 - outlineWeight); + } + else if (outlineStyle == OutlineStyleSquare) { + bool isOutsideY = abs(centeredTexCoords.y) > (1.0 - outlineWeight); + bool isOutsideX = abs(centeredTexCoords.x) > (1.0 - outlineWeight); + pixelIsOutline = isOutsideY || isOutsideX; + } + else if (outlineStyle == OutlineStyleBottom) { + pixelIsOutline = texCoord.y < 0.5 * outlineWeight; + } + + if (pixelIsOutline) { + vec4 theOutlineColor = vec4(outlineColor, 1.0); + if (useColorMap && useCmapOutline) { + theOutlineColor = cmapColor; + } + fullColor = theOutlineColor; + } } fullColor.a *= opacity * fadeInValue;