From adcd62deddf86549cdeeb3bfffc0e00c3c740788 Mon Sep 17 00:00:00 2001 From: Oskar Carlbaum Date: Wed, 4 Oct 2017 03:43:32 +0200 Subject: [PATCH] Add DomainLimiting, Masking and AdditiveBlending options --- .../renderablefieldlinessequence.cpp | 67 +++++++++- .../rendering/renderablefieldlinessequence.h | 24 +++- .../renderablefieldlinessequencesetup.cpp | 122 ++++++++++++++++++ .../shaders/fieldlinessequence_fs.glsl | 6 + .../shaders/fieldlinessequence_vs.glsl | 62 +++++++-- 5 files changed, 266 insertions(+), 15 deletions(-) diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp index 0e23cb81ed..2c8fc0b729 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp @@ -48,6 +48,9 @@ void RenderableFieldlinesSequence::deinitialize() { glDeleteBuffers(1, &_vertexColorBuffer); _vertexColorBuffer = 0; + glDeleteBuffers(1, &_vertexMaskingBuffer); + _vertexMaskingBuffer = 0; + RenderEngine& renderEngine = OsEng.renderEngine(); if (_shaderProgram) { renderEngine.removeRenderProgram(_shaderProgram); @@ -82,6 +85,8 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks& _shaderProgram->setUniform("colorMethod", _pColorMethod); _shaderProgram->setUniform("lineColor", _pColorUniform); + _shaderProgram->setUniform("usingDomain", _pDomainEnabled); + _shaderProgram->setUniform("usingMasking", _pMaskingEnabled); if (_pColorMethod == ColorMethod::BY_QUANTITY) { ghoul::opengl::TextureUnit textureUnit; @@ -92,6 +97,15 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks& _colorTableRanges[_pColorQuantity]); } + if (_pMaskingEnabled) { + _shaderProgram->setUniform("maskingRange", _maskingRanges[_pMaskingQuantity]); + } + + _shaderProgram->setUniform("domainLimR", _pDomainR.value() * _scalingFactor); + _shaderProgram->setUniform("domainLimX", _pDomainX.value() * _scalingFactor); + _shaderProgram->setUniform("domainLimY", _pDomainY.value() * _scalingFactor); + _shaderProgram->setUniform("domainLimZ", _pDomainZ.value() * _scalingFactor); + // Flow/Particles _shaderProgram->setUniform("flowColor", _pFlowColor); _shaderProgram->setUniform("usingParticles", _pFlowEnabled); @@ -100,6 +114,26 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks& _shaderProgram->setUniform("particleSpeed", _pFlowSpeed); _shaderProgram->setUniform("time", OsEng.runTime() * (_pFlowReversed ? -1 : 1)); + bool additiveBlending = false; + if (_pColorABlendEnabled) { + const auto RENDERER = OsEng.renderEngine().rendererImplementation(); + bool usingFBufferRenderer = RENDERER == + RenderEngine::RendererImplementation::Framebuffer; + + bool usingABufferRenderer = RENDERER == + RenderEngine::RendererImplementation::ABuffer; + + if (usingABufferRenderer) { + _shaderProgram->setUniform("usingAdditiveBlending", _pColorABlendEnabled); + } + + additiveBlending = usingFBufferRenderer; + if (additiveBlending) { + glDepthMask(false); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } + } + glBindVertexArray(_vertexArrayObject); glMultiDrawArrays( GL_LINE_STRIP, //_drawingOutputType, @@ -110,6 +144,11 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks& glBindVertexArray(0); _shaderProgram->deactivate(); + + if (additiveBlending) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(true); + } } } @@ -164,7 +203,8 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) { updateVertexPositionBuffer(); if (_states[_activeStateIndex].nExtraQuantities() > 0) { - _shouldUpdateColorBuffer = true; + _shouldUpdateColorBuffer = true; + _shouldUpdateMaskingBuffer = true; } else { _pColorMethod = ColorMethod::UNIFORM; } @@ -178,6 +218,11 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) { updateVertexColorBuffer(); _shouldUpdateColorBuffer = false; } + + if (_shouldUpdateMaskingBuffer) { + updateVertexMaskingBuffer(); + _shouldUpdateMaskingBuffer = false; + } } } @@ -252,6 +297,26 @@ void RenderableFieldlinesSequence::updateVertexColorBuffer() { } } +void RenderableFieldlinesSequence::updateVertexMaskingBuffer() { + glBindVertexArray(_vertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER, _vertexMaskingBuffer); + + bool isSuccessful; + const std::vector& QUANTITY_VEC = + _states[_activeStateIndex].extraQuantity(_pMaskingQuantity, isSuccessful); + + if (isSuccessful) { + glBufferData(GL_ARRAY_BUFFER, QUANTITY_VEC.size() * sizeof(float), + &QUANTITY_VEC.front(), GL_STATIC_DRAW); + + glEnableVertexAttribArray(_VA_MASKING); + glVertexAttribPointer(_VA_MASKING, 1, GL_FLOAT, GL_FALSE, 0, 0); + + unbindGL(); + } +} + + diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h index e138591c90..6302b43abf 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -75,8 +76,10 @@ private: bool _mustLoadNewStateFromDisk = false; bool _needsUpdate = false; // If still in same state as previous frame == false bool _shouldUpdateColorBuffer = false; + bool _shouldUpdateMaskingBuffer = false; FieldlinesState _newState; - size_t _nStates = 0; + size_t _nStates = 0; + float _scalingFactor = 1.f; double _sequenceEndTime; SourceFileType _sourceFileType; @@ -92,15 +95,18 @@ private: std::vector _startTimes; std::vector _states; std::vector _colorTableRanges; // Values represents min & max values represented in the color table + std::vector _maskingRanges; // Values represents min & max values for valid masking range GLuint _vertexArrayObject = 0; GLuint _vertexPositionBuffer = 0; GLuint _vertexColorBuffer = 0; + GLuint _vertexMaskingBuffer = 0; // THESE MUST CORRESPOND TO THE SHADER PROGRAM // TODO: THIS CAN BE DETERMINED BY ASKING THE SHADER PROGRAM TOO const GLuint _VA_POSITION = 0; const GLuint _VA_COLOR = 1; + const GLuint _VA_MASKING = 2; // ----------------------------- Properties ----------------------------- properties::PropertyOwner _pColorGroup; // Group to hold the color properties @@ -110,6 +116,14 @@ private: properties::StringProperty _pColorQuantityMax; // Color table/transfer function max properties::StringProperty _pColorTablePath; // Color table/transfer function for "By Quantity" coloring properties::Vec4Property _pColorUniform; // Uniform Field Line Color + properties::BoolProperty _pColorABlendEnabled; // Whether or not to use additive blending + + properties::BoolProperty _pDomainEnabled; // Whether or not to use Domain + properties::PropertyOwner _pDomainGroup; // Group to hold the Domain properties + properties::Vec2Property _pDomainX; // Domain Limits along x-axis + properties::Vec2Property _pDomainY; // Domain Limits along y-axis + properties::Vec2Property _pDomainZ; // Domain Limits along z-axis + properties::Vec2Property _pDomainR; // Domain Limits radially properties::Vec4Property _pFlowColor; // Simulated particles' color properties::BoolProperty _pFlowEnabled; // Toggle flow [ON/OFF] @@ -119,6 +133,12 @@ private: properties::BoolProperty _pFlowReversed; // Toggle flow direction [FORWARDS/BACKWARDS] properties::IntProperty _pFlowSpeed; // Speed of simulated flow + properties::BoolProperty _pMaskingEnabled; // Whether or not to use masking + properties::PropertyOwner _pMaskingGroup; // Group to hold the masking properties + properties::StringProperty _pMaskingMin; // Lower limit for allowed values + properties::StringProperty _pMaskingMax; // Upper limit for allowed values + properties::OptionProperty _pMaskingQuantity; // Index of the extra quantity to use for masking + properties::TriggerProperty _pFocusOnOriginBtn; // Button which sets camera focus to parent node of the renderable properties::TriggerProperty _pJumpToStartBtn; // Button which executes a time jump to start of sequence @@ -136,6 +156,8 @@ private: void definePropertyCallbackFunctions(); void setupProperties(); + + void setModelDependentConstants(); }; } // namespace openspace diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp b/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp index d2811e5ef4..ff1c7f14ad 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequencesetup.cpp @@ -44,6 +44,7 @@ namespace { // ---------------------------- OPTIONAL MODFILE KEYS ---------------------------- // const char* KEY_COLOR_TABLE_PATHS = "ColorTablePaths"; // [STRING ARRAY] Values should be paths to .txt files const char* KEY_COLOR_TABLE_RANGES = "ColorTableRanges";// [VEC2 ARRAY] Values should be entered as {X, Y}, where X & Y are numbers + const char* KEY_MASKING_RANGES = "MaskingRanges"; // [VEC2 ARRAY] Values should be entered as {X, Y}, where X & Y are numbers const char* KEY_OSLFS_LOAD_AT_RUNTIME = "LoadAtRuntime"; // [BOOLEAN] If value False => Load in initializing step and store in RAM // ------------- POSSIBLE STRING VALUES FOR CORRESPONDING MODFILE KEY ------------- // @@ -70,6 +71,24 @@ namespace { static const openspace::properties::Property::PropertyInfo ColorUniformInfo = { "uniform", "Uniform Line Color", "The uniform color of lines shown when \"Color Method\" is set to \"Uniform\"." }; + static const openspace::properties::Property::PropertyInfo ColorUseABlendingInfo = { + "aBlendingEnabled", "Additive Blending", "Activate/deactivate additive blending." + }; + static const openspace::properties::Property::PropertyInfo DomainEnabledInfo = { + "domainEnabled", "Domain Limits", "Enable/Disable domain limits" + }; + static const openspace::properties::Property::PropertyInfo DomainXInfo = { + "limitsX", "X-limits", "Valid range along the X-axis. [Min, Max]" + }; + static const openspace::properties::Property::PropertyInfo DomainYInfo = { + "limitsY", "Y-limits", "Valid range along the Y-axis. [Min, Max]" + }; + static const openspace::properties::Property::PropertyInfo DomainZInfo = { + "limitsZ", "Z-limits", "Valid range along the Z-axis. [Min, Max]" + }; + static const openspace::properties::Property::PropertyInfo DomainRInfo = { + "limitsR", "Radial limits", "Valid radial range. [Min, Max]" + }; static const openspace::properties::Property::PropertyInfo FlowColorInfo = { "color", "Color", "Color of particles." }; @@ -89,6 +108,19 @@ namespace { static const openspace::properties::Property::PropertyInfo FlowSpeedInfo = { "speed", "Speed", "Speed of the flow." }; + static const openspace::properties::Property::PropertyInfo MaskingEnabledInfo = { + "maskingEnabled", "Masking", + "Enable/disable masking. Use masking to show lines where a given quantity is within a given range, e.g. if you only want to see where the temperature is between 10 and 20 degrees. Also used for masking out line topologies like solar wind & closed lines." + }; + static const openspace::properties::Property::PropertyInfo MaskingMinInfo = { + "maskingMinLimit", "Lower Limit", "Lower limit of the valid masking range" + }; + static const openspace::properties::Property::PropertyInfo MaskingMaxInfo = { + "maskingMaxLimit", "Upper Limit", "Upper limit of the valid masking range" + }; + static const openspace::properties::Property::PropertyInfo MaskingQuantityInfo = { + "maskingQuantity", "Quantity used for Masking", "Quantity used for masking." + }; static const openspace::properties::Property::PropertyInfo OriginButtonInfo = { "focusCameraOnParent", "Focus Camera", "Focus camera on parent." }; @@ -121,6 +153,13 @@ RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictiona _pColorTablePath(ColorTablePathInfo), _pColorUniform(ColorUniformInfo, glm::vec4(0.75f, 0.5f, 0.0f, 0.5f), glm::vec4(0.f), glm::vec4(1.f)), + _pColorABlendEnabled(ColorUseABlendingInfo, true), + _pDomainEnabled(DomainEnabledInfo, true), + _pDomainGroup({ "Domain" }), + _pDomainX(DomainXInfo), + _pDomainY(DomainYInfo), + _pDomainZ(DomainZInfo), + _pDomainR(DomainRInfo), _pFlowColor(FlowColorInfo, glm::vec4(0.8f, 0.7f, 0.0f, 0.6f), glm::vec4(0.f), glm::vec4(1.f)), _pFlowEnabled(FlowEnabledInfo, true), @@ -129,6 +168,11 @@ RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictiona _pFlowParticleSpacing(FlowParticleSpacingInfo, 60, 0, 500), _pFlowReversed(FlowReversedInfo, false), _pFlowSpeed(FlowSpeedInfo, 20, 0, 1000), + _pMaskingEnabled(MaskingEnabledInfo, false), + _pMaskingGroup({ "Masking" }), + _pMaskingMin(MaskingMinInfo), + _pMaskingMax(MaskingMaxInfo), + _pMaskingQuantity(MaskingQuantityInfo, properties::OptionProperty::DisplayType::Dropdown), _pFocusOnOriginBtn(OriginButtonInfo), _pJumpToStartBtn(TimeJumpButtonInfo) { @@ -191,6 +235,7 @@ void RenderableFieldlinesSequence::initialize() { } computeSequenceEndTime(); + setModelDependentConstants(); setupProperties(); @@ -210,6 +255,10 @@ void RenderableFieldlinesSequence::initialize() { glGenVertexArrays(1, &_vertexArrayObject); glGenBuffers(1, &_vertexPositionBuffer); glGenBuffers(1, &_vertexColorBuffer); + glGenBuffers(1, &_vertexMaskingBuffer); + + // Needed for additive blending + setRenderBin(Renderable::RenderBin::Overlay); } bool RenderableFieldlinesSequence::extractInfoFromDictionary( @@ -327,13 +376,18 @@ bool RenderableFieldlinesSequence::extractInfoFromDictionary( void RenderableFieldlinesSequence::setupProperties() { // -------------- Add non-grouped properties (enablers and buttons) -------------- // + addProperty(_pColorABlendEnabled); + addProperty(_pDomainEnabled); addProperty(_pFlowEnabled); + addProperty(_pMaskingEnabled); addProperty(_pFocusOnOriginBtn); addProperty(_pJumpToStartBtn); // ----------------------------- Add Property Groups ----------------------------- // addPropertySubOwner(_pColorGroup); + addPropertySubOwner(_pDomainGroup); addPropertySubOwner(_pFlowGroup); + addPropertySubOwner(_pMaskingGroup); // ------------------------- Add Properties to the groups ------------------------- // _pColorGroup.addProperty(_pColorMethod); @@ -343,12 +397,21 @@ void RenderableFieldlinesSequence::setupProperties() { _pColorGroup.addProperty(_pColorTablePath); _pColorGroup.addProperty(_pColorUniform); + _pDomainGroup.addProperty(_pDomainX); + _pDomainGroup.addProperty(_pDomainY); + _pDomainGroup.addProperty(_pDomainZ); + _pDomainGroup.addProperty(_pDomainR); + _pFlowGroup.addProperty(_pFlowReversed); _pFlowGroup.addProperty(_pFlowColor); _pFlowGroup.addProperty(_pFlowParticleSize); _pFlowGroup.addProperty(_pFlowParticleSpacing); _pFlowGroup.addProperty(_pFlowSpeed); + _pMaskingGroup.addProperty(_pMaskingMin); + _pMaskingGroup.addProperty(_pMaskingMax); + _pMaskingGroup.addProperty(_pMaskingQuantity); + // ----------------------- Add Options to OptionProperties ----------------------- // _pColorMethod.addOption(ColorMethod::UNIFORM, "Uniform"); _pColorMethod.addOption(ColorMethod::BY_QUANTITY, "By Quantity"); @@ -360,10 +423,12 @@ void RenderableFieldlinesSequence::setupProperties() { auto EXTRA_VARIABLE_NAMES_VEC = _states[0].extraQuantityNames(); for (int i = 0; i < N_EXTRA_QUANTITIES; ++i) { _pColorQuantity.addOption(i, EXTRA_VARIABLE_NAMES_VEC[i]); + _pMaskingQuantity.addOption(i, EXTRA_VARIABLE_NAMES_VEC[i]); } // Each quantity should have its own color table and color table range, no more, no less _colorTablePaths.resize(N_EXTRA_QUANTITIES, _colorTablePaths.back()); _colorTableRanges.resize(N_EXTRA_QUANTITIES, _colorTableRanges.back()); + _maskingRanges.resize(N_EXTRA_QUANTITIES, _maskingRanges.back()); definePropertyCallbackFunctions(); @@ -373,6 +438,10 @@ void RenderableFieldlinesSequence::setupProperties() { _pColorQuantityMax = std::to_string(_colorTableRanges[_pColorQuantity].y); _pColorTablePath = _colorTablePaths[_pColorQuantity]; + _pMaskingQuantity = 0; + _pMaskingMin = std::to_string(_maskingRanges[_pMaskingQuantity].x); + _pMaskingMax = std::to_string(_maskingRanges[_pMaskingQuantity].y); + } void RenderableFieldlinesSequence::definePropertyCallbackFunctions() { @@ -404,6 +473,27 @@ void RenderableFieldlinesSequence::definePropertyCallbackFunctions() { _colorTableRanges[_pColorQuantity].y = f; }); + _pMaskingQuantity.onChange([this] { + LDEBUG("CHANGED MASKING QUANTITY"); + _shouldUpdateMaskingBuffer = true; + _pMaskingMin = std::to_string(_maskingRanges[_pMaskingQuantity].x); + _pMaskingMax = std::to_string(_maskingRanges[_pMaskingQuantity].y); + }); + + _pMaskingMin.onChange([this] { + LDEBUG("CHANGED LOWER MASKING LIMIT"); + float f = stringToFloat(_pMaskingMin, _maskingRanges[_pMaskingQuantity].x); + _pMaskingMin = std::to_string(f); + _maskingRanges[_pMaskingQuantity].x = f; + }); + + _pMaskingMax.onChange([this] { + LDEBUG("CHANGED UPPER MASKING LIMIT"); + float f = stringToFloat(_pMaskingMax, _maskingRanges[_pMaskingQuantity].y); + _pMaskingMax = std::to_string(f); + _maskingRanges[_pMaskingQuantity].y = f; + }); + _pFocusOnOriginBtn.onChange([this] { LDEBUG("SET FOCUS NODE TO PARENT"); SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(_name); @@ -435,6 +525,38 @@ void RenderableFieldlinesSequence::computeSequenceEndTime() { } } +void RenderableFieldlinesSequence::setModelDependentConstants() { + const fls::Model simulationModel = _states[0].model(); + float limit = 100.f; // Just used as a default value. + switch (simulationModel) { + case fls::Model::BATSRUS: + _scalingFactor = fls::R_E_TO_METER; + limit = 300; // Should include a long magnetotail + break; + case fls::Model::ENLIL: + _pFlowReversed = true; + _scalingFactor = fls::A_U_TO_METER; + limit = 50; // Should include Plutos furthest distance from the Sun + break; + case fls::Model::PFSS: + _scalingFactor = fls::R_S_TO_METER; + limit = 100; // Just a default value far away from the solar surface + break; + default: + break; + } + _pDomainX.setMinValue(glm::vec2(-limit)); _pDomainX.setMaxValue(glm::vec2(limit)); + _pDomainY.setMinValue(glm::vec2(-limit)); _pDomainY.setMaxValue(glm::vec2(limit)); + _pDomainZ.setMinValue(glm::vec2(-limit)); _pDomainZ.setMaxValue(glm::vec2(limit)); + // Radial should range from 0 out to a corner of the cartesian box: sqrt(3) = 1.732..., 1.75 is a nice and round number + _pDomainR.setMinValue(glm::vec2(0)); _pDomainR.setMaxValue(glm::vec2(limit*1.75f)); + + _pDomainX = glm::vec2(-limit, limit); + _pDomainY = glm::vec2(-limit, limit); + _pDomainZ = glm::vec2(-limit, limit); + _pDomainR = glm::vec2(0, limit*1.5f); +} + // Extract J2000 time from file names // Requires files to be named as such: 'YYYY-MM-DDTHH-MM-SS-XXX.osfls' void RenderableFieldlinesSequence::extractTriggerTimesFromFileNames() { diff --git a/modules/fieldlinessequence/shaders/fieldlinessequence_fs.glsl b/modules/fieldlinessequence/shaders/fieldlinessequence_fs.glsl index 8e8f3ec6d3..47f3c6ac2d 100644 --- a/modules/fieldlinessequence/shaders/fieldlinessequence_fs.glsl +++ b/modules/fieldlinessequence/shaders/fieldlinessequence_fs.glsl @@ -25,6 +25,8 @@ in vec4 vs_color; in float vs_depth; +uniform bool usingAdditiveBlending; + #include "fragment.glsl" #include "PowerScaling/powerScaling_fs.hglsl" @@ -39,5 +41,9 @@ Fragment getFragment() { frag.depth = vs_depth; frag.color = fragColor; + if (usingAdditiveBlending) { + frag.blend = BLEND_MODE_ADDITIVE; + } + return frag; } diff --git a/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl b/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl index de0bd246a6..8491716b29 100644 --- a/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl +++ b/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl @@ -43,8 +43,21 @@ uniform int particleSpacing; uniform double time; uniform bool usingParticles; -layout(location = 0) in vec3 in_position; // Should be provided in meters -layout(location = 1) in float in_color_scalar; // The extra value used to color lines. Location must correspond to _VA_COLOR in renderablefieldlinessequence.h +// Masking Uniforms +uniform bool usingMasking; +uniform vec2 maskingRange; + +// Domain Uniforms +uniform bool usingDomain; +uniform vec2 domainLimX; +uniform vec2 domainLimY; +uniform vec2 domainLimZ; +uniform vec2 domainLimR; + +// Inputs +layout(location = 0) in vec3 in_position; // Should be provided in meters +layout(location = 1) in float in_color_scalar; // The extra value used to color lines. Location must correspond to _VA_COLOR in renderablefieldlinessequence.h +layout(location = 2) in float in_masking_scalar; // The extra value used to mask out parts of lines. Location must correspond to _VA_MASKING in renderablefieldlinessequence.h // These should correspond to the enum 'ColorMethod' in renderablefieldlinesequence.cpp const int UNIFORM_COLOR = 0; @@ -69,20 +82,43 @@ bool isPartOfParticle(const double TIME, const int VERTEX_ID, const int PARTICLE void main() { - const bool IS_PARTICLE = usingParticles && isPartOfParticle(time, gl_VertexID, - particleSize, - particleSpeed, - particleSpacing); + bool hasColor = true; - if (IS_PARTICLE) { - vs_color = flowColor; - } else { - vs_color = lineColor; + if (usingMasking && (in_masking_scalar < maskingRange.x || + in_masking_scalar > maskingRange.y )) { + hasColor = false; } - if (colorMethod == COLOR_BY_QUANTITY) { - const vec4 QUANTITY_COLOR = getTransferFunctionColor(); - vs_color = vec4(QUANTITY_COLOR.xyz, vs_color.a * QUANTITY_COLOR.a); + if (usingDomain && hasColor) { + const float RADIUS = length(in_position); + + if (in_position.x < domainLimX.x || in_position.x > domainLimX.y || + in_position.y < domainLimY.x || in_position.y > domainLimY.y || + in_position.z < domainLimZ.x || in_position.z > domainLimZ.y || + RADIUS < domainLimR.x || RADIUS > domainLimR.y) { + + hasColor = false; + } + } + + if (hasColor) { + const bool IS_PARTICLE = usingParticles && isPartOfParticle(time, gl_VertexID, + particleSize, + particleSpeed, + particleSpacing); + + if (IS_PARTICLE) { + vs_color = flowColor; + } else { + vs_color = lineColor; + } + + if (colorMethod == COLOR_BY_QUANTITY) { + const vec4 QUANTITY_COLOR = getTransferFunctionColor(); + vs_color = vec4(QUANTITY_COLOR.xyz, vs_color.a * QUANTITY_COLOR.a); + } + } else { + vs_color = vec4(0); } vec4 position_in_meters = vec4(in_position, 1);