From 0bc6036beb909d12749bf014fdbf32aa9ba40194 Mon Sep 17 00:00:00 2001 From: Jacob Molin Date: Wed, 8 Jun 2022 13:56:24 -0600 Subject: [PATCH] Adds feature to choose via SIMP how colormap attribute NaN values should be rendered --- .../pointdatamessagehandler.cpp | 45 +++++++++ .../rendering/renderablepointscloud.cpp | 94 +++++++++++++------ .../rendering/renderablepointscloud.h | 7 +- .../softwareintegration/shaders/point_fs.glsl | 19 +++- .../softwareintegration/shaders/point_ge.glsl | 1 + modules/softwareintegration/utils.cpp | 5 + modules/softwareintegration/utils.h | 13 +++ 7 files changed, 148 insertions(+), 36 deletions(-) diff --git a/modules/softwareintegration/pointdatamessagehandler.cpp b/modules/softwareintegration/pointdatamessagehandler.cpp index 4810b8b306..b6e62b4c98 100644 --- a/modules/softwareintegration/pointdatamessagehandler.cpp +++ b/modules/softwareintegration/pointdatamessagehandler.cpp @@ -143,11 +143,24 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector& mes float min; float max; + simp::CmapNaNMode cmapNaNMode; + glm::vec4 cmapNaNColor; size_t nColors; std::vector colorMap; try { min = simp::readFloatValue(message, messageOffset); max = simp::readFloatValue(message, messageOffset); + cmapNaNMode = simp::getCmapNaNMode(simp::readString(message, messageOffset)); + switch (cmapNaNMode) { + case simp::CmapNaNMode::Color: + cmapNaNColor = simp::readColor(message, messageOffset); + break; + case simp::CmapNaNMode::Hide: // Nothing to read + break; + default: // simp::CmapNaNMode::Unknown + // TODO: Throw SimpError + break; + } nColors = static_cast(simp::readIntValue(message, messageOffset)); simp::readColormap(message, messageOffset, nColors, colorMap); } @@ -199,6 +212,38 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector& mes }; addCallback(identifier, { colormapLimitsCallback, {}, "colormapLimitsCallback" }); + auto cmapNaNModeCallback = [this, identifier, cmapNaNMode, cmapNaNColor, connection] { + + if (cmapNaNMode == simp::CmapNaNMode::Color) { + // Get renderable + auto r = getRenderable(identifier); + + // Get cmapNaNColor of renderable + properties::Property* cmapNaNColorProperty = r->property("CmapNaNColor"); + glm::vec4 propertyCmapNaNColor = std::any_cast(cmapNaNColorProperty->get()); + + // Update cmapNaNColor of renderable + if (propertyCmapNaNColor != cmapNaNColor) { + global::scriptEngine->queueScript( + fmt::format( + "openspace.setPropertyValueSingle('Scene.{}.Renderable.CmapNaNColor', {});", + identifier, ghoul::to_string(cmapNaNColor) + ), + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + } + + global::scriptEngine->queueScript( + fmt::format( + "openspace.setPropertyValueSingle('Scene.{}.Renderable.CmapNaNMode', {});", + identifier, static_cast(cmapNaNMode) + ), + scripting::ScriptEngine::RemoteScripting::Yes + ); + }; + addCallback(identifier, { cmapNaNModeCallback, {}, "cmapNaNModeCallback" }); + auto enableColormapCallback = [this, identifier] { global::scriptEngine->queueScript( fmt::format( diff --git a/modules/softwareintegration/rendering/renderablepointscloud.cpp b/modules/softwareintegration/rendering/renderablepointscloud.cpp index 496625105f..52519002db 100644 --- a/modules/softwareintegration/rendering/renderablepointscloud.cpp +++ b/modules/softwareintegration/rendering/renderablepointscloud.cpp @@ -45,11 +45,12 @@ namespace { constexpr const char* _loggerCat = "PointsCloud"; - constexpr const std::array UniformNames = { + constexpr const std::array UniformNames = { "color", "opacity", "size", "modelMatrix", "cameraUp", "screenSize", - "cameraViewProjectionMatrix", "eyePosition", "sizeOption", "colormapTexture", - "colormapMin", "colormapMax", "colormapEnabled", "linearSizeMin", - "linearSizeMax", "linearSizeEnabled" + "cameraViewProjectionMatrix", "eyePosition", "sizeOption", + "colormapTexture", "colormapMin", "colormapMax", "cmapNaNMode", + "cmapNaNColor", "colormapEnabled", "linearSizeMin", "linearSizeMax", + "linearSizeEnabled" }; constexpr openspace::properties::Property::PropertyInfo ColorInfo = { @@ -93,6 +94,18 @@ namespace { "Colormap max", "Maximum value to sample from color map." }; + + constexpr openspace::properties::Property::PropertyInfo CmapNaNModeInfo = { + "CmapNaNMode", + "Cmap NaN Mode", + "How points with NaN value in colormap attribute should be represented." + }; + + constexpr openspace::properties::Property::PropertyInfo CmapNaNColorInfo = { + "CmapNaNColor", + "Cmap NaN Color", + "The color of the points where the colormap scalar is NaN." + }; constexpr openspace::properties::Property::PropertyInfo ColormapEnabledInfo = { "ColormapEnabled", @@ -136,6 +149,12 @@ namespace { // [[codegen::verbatim(ColormapMaxInfo.description)]] std::optional colormapMax; + + // [[codegen::verbatim(CmapNaNModeInfo.description)]] + std::optional cmapNaNMode; + + // [[codegen::verbatim(CmapNaNColorInfo.description)]] + std::optional cmapNaNColor; // [[codegen::verbatim(ColormapEnabledInfo.description)]] std::optional colormapEnabled; @@ -172,34 +191,45 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary , _color(ColorInfo, glm::vec4(glm::vec3(0.5f), 1.f), glm::vec4(0.f), glm::vec4(1.f), glm::vec4(.01f)) , _size(SizeInfo, 1.f, 0.f, 500.f, .1f) , _sizeOption(SizeOptionInfo, properties::OptionProperty::DisplayType::Dropdown) - , _colormapEnabled(ColormapEnabledInfo, false) , _colormapMin(ColormapMinInfo) , _colormapMax(ColormapMaxInfo) + , _cmapNaNMode(CmapNaNModeInfo) + , _cmapNaNColor(CmapNaNColorInfo, glm::vec4(glm::vec3(0.5f), 1.f), glm::vec4(1.0f), glm::vec4(0.f), glm::vec4(0.f)) + , _colormapEnabled(ColormapEnabledInfo, false) , _linearSizeMax(LinearSizeMinInfo) , _linearSizeMin(LinearSizeMaxInfo) , _linearSizeEnabled(LinearSizeEnabledInfo) { const Parameters p = codegen::bake(dictionary); + _identifier = p.identifier.value(); + _color = p.color.value_or(_color); _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - _colormapEnabled = p.colormapEnabled.value_or(_colormapEnabled); - _colormapEnabled.onChange([this] { checkIfColormapCanBeEnabled(); }); - addProperty(_colormapEnabled); - - _identifier = p.identifier.value(); - _size = p.size.value_or(_size); addProperty(_size); - _linearSizeEnabled = p.linearSizeEnabled.value_or(_linearSizeEnabled); - _linearSizeEnabled.onChange([this] { checkIfLinearSizeCanBeEnabled(); }); - addProperty(_linearSizeEnabled); + _sizeOption.addOptions({ + { SizeOption::Uniform, "Uniform" }, + { SizeOption::NonUniform, "Non uniform" } + }); + if (p.sizeOption.has_value()) { + switch (*p.sizeOption) { + case Parameters::SizeOption::Uniform: + _sizeOption = SizeOption::Uniform; + break; + case Parameters::SizeOption::NonUniform: + _sizeOption = SizeOption::NonUniform; + break; + } + } + addProperty(_sizeOption); addProperty(_opacity); + // =============== Colormap =============== _colormapMin = p.colormapMin.value_or(_colormapMin); _colormapMin.setVisibility(properties::Property::Visibility::Hidden); _colormapMin.onChange([this] { checkColormapMinMax(); }); @@ -210,6 +240,24 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary _colormapMax.onChange([this] { checkColormapMinMax(); }); addProperty(_colormapMax); + _cmapNaNMode = p.cmapNaNMode.value_or(_cmapNaNMode); + _cmapNaNMode.setVisibility(properties::Property::Visibility::Hidden); + addProperty(_cmapNaNMode); + + _cmapNaNColor = p.cmapNaNColor.value_or(_cmapNaNColor); + // _cmapNaNColor.setViewOption(properties::Property::ViewOptions::Color); // TODO: CHECK WHAT THIS IS + _cmapNaNColor.setVisibility(properties::Property::Visibility::Hidden); + addProperty(_cmapNaNColor); + + _colormapEnabled = p.colormapEnabled.value_or(_colormapEnabled); + _colormapEnabled.onChange([this] { checkIfColormapCanBeEnabled(); }); + addProperty(_colormapEnabled); + + // =============== Linear size =============== + _linearSizeEnabled = p.linearSizeEnabled.value_or(_linearSizeEnabled); + _linearSizeEnabled.onChange([this] { checkIfLinearSizeCanBeEnabled(); }); + addProperty(_linearSizeEnabled); + auto linearSizeMinMaxChecker = [this] { if (_linearSizeMin.value() > _linearSizeMax.value()) { auto temp = _linearSizeMin.value(); @@ -227,22 +275,6 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary _linearSizeMax.setVisibility(properties::Property::Visibility::Hidden); _linearSizeMax.onChange(linearSizeMinMaxChecker); addProperty(_linearSizeMax); - - _sizeOption.addOptions({ - { SizeOption::Uniform, "Uniform" }, - { SizeOption::NonUniform, "Non uniform" } - }); - if (p.sizeOption.has_value()) { - switch (*p.sizeOption) { - case Parameters::SizeOption::Uniform: - _sizeOption = SizeOption::Uniform; - break; - case Parameters::SizeOption::NonUniform: - _sizeOption = SizeOption::NonUniform; - break; - } - } - addProperty(_sizeOption); } bool RenderablePointsCloud::isReady() const { @@ -327,6 +359,8 @@ void RenderablePointsCloud::render(const RenderData& data, RendererTasks&) { _shaderProgram->setUniform(_uniformCache.colormapMin, _colormapMin); _shaderProgram->setUniform(_uniformCache.colormapMax, _colormapMax); + _shaderProgram->setUniform(_uniformCache.cmapNaNMode, _cmapNaNMode); + _shaderProgram->setUniform(_uniformCache.cmapNaNColor, _cmapNaNColor); _shaderProgram->setUniform(_uniformCache.colormapEnabled, _colormapEnabled); _shaderProgram->setUniform(_uniformCache.linearSizeMin, _linearSizeMin); diff --git a/modules/softwareintegration/rendering/renderablepointscloud.h b/modules/softwareintegration/rendering/renderablepointscloud.h index 17a8652081..c34762f875 100644 --- a/modules/softwareintegration/rendering/renderablepointscloud.h +++ b/modules/softwareintegration/rendering/renderablepointscloud.h @@ -78,8 +78,9 @@ protected: UniformCache( color, opacity, size, modelMatrix, cameraUp, screenSize, cameraViewProjectionMatrix, eyePosition, sizeOption, - colormapTexture, colormapMin, colormapMax, colormapEnabled, - linearSizeMin, linearSizeMax, linearSizeEnabled + colormapTexture, colormapMin, colormapMax, cmapNaNMode, + cmapNaNColor, colormapEnabled, linearSizeMin, linearSizeMax, + linearSizeEnabled ) _uniformCache; properties::FloatProperty _size; @@ -93,6 +94,8 @@ protected: properties::BoolProperty _colormapEnabled; properties::FloatProperty _colormapMin; properties::FloatProperty _colormapMax; + properties::IntProperty _cmapNaNMode; + properties::Vec4Property _cmapNaNColor; std::optional _identifier = std::nullopt; diff --git a/modules/softwareintegration/shaders/point_fs.glsl b/modules/softwareintegration/shaders/point_fs.glsl index 3042552fe6..715d919f61 100644 --- a/modules/softwareintegration/shaders/point_fs.glsl +++ b/modules/softwareintegration/shaders/point_fs.glsl @@ -25,6 +25,9 @@ #include "fragment.glsl" #include "PowerScaling/powerScaling_fs.hglsl" +const int CMAPNANMODE_HIDDEN = 0; +const int CMAPNANMODE_COLOR = 1; + flat in float ge_colormapAttributeScalar; in vec2 coords; flat in float ge_screenSpaceDepth; @@ -36,6 +39,8 @@ uniform float opacity; uniform float colormapMin; uniform float colormapMax; +uniform int cmapNaNMode; +uniform vec4 cmapNaNColor; uniform bool colormapEnabled; uniform sampler1D colormapTexture; @@ -55,8 +60,8 @@ Fragment getFragment() { discard; } - // Don't show points with no value for that attribute - if (colormapEnabled && isnan(ge_colormapAttributeScalar)) { + // Don't show points with no value for that attribute, if CmapNaNMode is Hidden + if (colormapEnabled && isnan(ge_colormapAttributeScalar) && cmapNaNMode == CMAPNANMODE_HIDDEN) { discard; } @@ -69,8 +74,14 @@ Fragment getFragment() { vec4 outputColor = vec4(color.rgb, color.a * opacity); if (colormapEnabled) { - vec4 colorFromColormap = attributeScalarToRgb(ge_colormapAttributeScalar); - outputColor = vec4(colorFromColormap.rgb, colorFromColormap.a * color.a * opacity); + // Set CmapNaNColor if point doesn't have a value for the attribute + if (isnan(ge_colormapAttributeScalar) && cmapNaNMode == CMAPNANMODE_COLOR) { + outputColor = vec4(cmapNaNColor.rgb, cmapNaNColor.a * opacity); + } + else { + vec4 colorFromColormap = attributeScalarToRgb(ge_colormapAttributeScalar); + outputColor = vec4(colorFromColormap.rgb, colorFromColormap.a * color.a * opacity); + } } Fragment frag; diff --git a/modules/softwareintegration/shaders/point_ge.glsl b/modules/softwareintegration/shaders/point_ge.glsl index 219e52a11c..46105d232a 100644 --- a/modules/softwareintegration/shaders/point_ge.glsl +++ b/modules/softwareintegration/shaders/point_ge.glsl @@ -104,6 +104,7 @@ void main() { if (linearSizeEnabled) { float interpolatedSizeAtt = 1.0; + // TODO: colormapAttributeScalar should be linearSizeAttributeScalar??? float colormapAttributeScalar = vs_linearSizeAttributeScalar[0]; if (colormapAttributeScalar < linearSizeMin) { interpolatedSizeAtt = 0.0; diff --git a/modules/softwareintegration/utils.cpp b/modules/softwareintegration/utils.cpp index 492a1bdf8a..29c363e7bd 100644 --- a/modules/softwareintegration/utils.cpp +++ b/modules/softwareintegration/utils.cpp @@ -105,6 +105,11 @@ std::string getSIMPType(const MessageType& type) { return it->first; } +CmapNaNMode getCmapNaNMode(const std::string& type) { + if (tools::_cmapNaNModeFromString.count(type) == 0) return CmapNaNMode::Unknown; + return tools::_cmapNaNModeFromString.at(type); +} + std::string formatLengthOfSubject(size_t lengthOfSubject) { // Format length of subject to always be 15 digits std::ostringstream os; diff --git a/modules/softwareintegration/utils.h b/modules/softwareintegration/utils.h index 6f31651a8d..cf616852ca 100644 --- a/modules/softwareintegration/utils.h +++ b/modules/softwareintegration/utils.h @@ -77,6 +77,12 @@ enum class MessageType : uint32_t { Unknown }; +enum class CmapNaNMode : uint32_t { + Hide = 0, + Color, + Unknown +}; + namespace tools { enum class ErrorCode : uint32_t { @@ -100,6 +106,11 @@ const std::unordered_map _messageTypeFromSIMPType { {"DISC", MessageType::Disconnection}, }; +const std::unordered_map _cmapNaNModeFromString { + {"Hide", CmapNaNMode::Hide}, + {"Color", CmapNaNMode::Color} +}; + glm::vec4 readSingleColor(const std::vector& message, size_t& offset); bool isEndOfCurrentValue(const std::vector& message, size_t offset); @@ -117,6 +128,8 @@ MessageType getMessageType(const std::string& type); std::string getSIMPType(const MessageType& type); +CmapNaNMode getCmapNaNMode(const std::string& type); + std::string formatLengthOfSubject(size_t lengthOfSubject);