diff --git a/modules/softwareintegration/CMakeLists.txt b/modules/softwareintegration/CMakeLists.txt index f940dbb39c..c557b3a213 100644 --- a/modules/softwareintegration/CMakeLists.txt +++ b/modules/softwareintegration/CMakeLists.txt @@ -49,6 +49,7 @@ source_group("Source Files" FILES ${SOURCE_FILES}) set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/point_vs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/point_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/point_ge.glsl ) source_group("Shader Files" FILES ${SHADER_FILES}) diff --git a/modules/softwareintegration/rendering/renderablepointscloud.cpp b/modules/softwareintegration/rendering/renderablepointscloud.cpp index 9639d20cc7..1df4766b2c 100644 --- a/modules/softwareintegration/rendering/renderablepointscloud.cpp +++ b/modules/softwareintegration/rendering/renderablepointscloud.cpp @@ -41,8 +41,9 @@ namespace { constexpr const char* _loggerCat = "PointsCloud"; - constexpr const std::array UniformNames = { - "modelViewTransform", "MVPTransform", "color", "opacity", "size", + constexpr const std::array UniformNames = { + "color", "opacity", "size", "modelMatrix", "cameraUp", + "cameraViewProjectionMatrix", "eyePosition", "sizeOption" }; constexpr openspace::properties::Property::PropertyInfo ColorInfo = { @@ -76,6 +77,12 @@ namespace { "big datasets with lots of points." }; + constexpr openspace::properties::Property::PropertyInfo SizeOptionInfo = { + "SizeOption", + "Size Option", + "This value determines how the size of the data points are rendered." + }; + struct [[codegen::Dictionary(RenderablePointsCloud)]] Parameters { // [[codegen::verbatim(ColorInfo.description)]] std::optional color; @@ -91,6 +98,13 @@ namespace { // [[codegen::verbatim(DataStorageKeyInfo.description)]] std::optional dataStorageKey; + + enum class SizeOption { + Uniform, + NonUniform + }; + // [[codegen::verbatim(SizeOptionInfo.description)]] + std::optional sizeOption; }; #include "renderablepointscloud_codegen.cpp" } // namespace @@ -106,6 +120,7 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary , _color(ColorInfo, glm::vec3(0.5f), glm::vec3(0.f), glm::vec3(1.f)) , _size(SizeInfo, 1.f, 0.f, 150.f) , _isVisible(ToggleVisibilityInfo, true) + , _sizeOption(SizeOptionInfo, properties::OptionProperty::DisplayType::Dropdown) { const Parameters p = codegen::bake(dictionary); @@ -113,23 +128,9 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - // If the data is passed explicitly, use that one. If not, check if a key to data - // stored in the module's centralized memory was included - if (p.data.has_value()) { - ghoul::Dictionary d = dictionary.value(DataInfo.identifier); - _pointData.reserve(d.size()); - - for (int i = 0; i < static_cast(d.size()); ++i) { - const std::string key = std::to_string(i + 1); - _pointData.push_back(d.value(key)); - } - _nValuesPerPoint = 3; - _nPoints = static_cast(_pointData.size()); - } - else if (p.dataStorageKey.has_value()) { - _nValuesPerPoint = 3; - _dataStorageKey = p.dataStorageKey.value(); - } + // Check if a key to data stored in the module's centralized memory was included + _nValuesPerPoint = 3; + _dataStorageKey = p.dataStorageKey.value(); _size = p.size.value_or(_size); addProperty(_size); @@ -138,6 +139,23 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary addProperty(_isVisible); addProperty(_opacity); + + _sizeOption.addOptions({ + { SizeOption::Uniform, "Uniform" }, + { SizeOption::NonUniform, "NonUniform" } + }); + if (p.sizeOption.has_value()) { + switch (*p.sizeOption) { + case Parameters::SizeOption::Uniform: + _sizeOption = SizeOption::Uniform; + break; + case Parameters::SizeOption::NonUniform: + _sizeOption = SizeOption::NonUniform; + break; + } + } + _sizeOption.onChange([&] { _isDirty = true; }); + addProperty(_sizeOption); } bool RenderablePointsCloud::isReady() const { @@ -152,7 +170,8 @@ void RenderablePointsCloud::initializeGL() { _shaderProgram = global::renderEngine->buildRenderProgram( "PointsCloud", absPath("${MODULE_SOFTWAREINTEGRATION}/shaders/point_vs.glsl"), - absPath("${MODULE_SOFTWAREINTEGRATION}/shaders/point_fs.glsl") + absPath("${MODULE_SOFTWAREINTEGRATION}/shaders/point_fs.glsl"), + absPath("${MODULE_SOFTWAREINTEGRATION}/shaders/point_ge.glsl") ); ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache, UniformNames); @@ -179,31 +198,40 @@ void RenderablePointsCloud::render(const RenderData& data, RendererTasks&) { if (!_isVisible) { return; } - + _shaderProgram->activate(); - glm::dmat4 modelTransform = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation - glm::dmat4(data.modelTransform.rotation) * // Spice rotation - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + glm::dvec3 eyePosition = glm::dvec3( + glm::inverse(data.camera.combinedViewMatrix()) * glm::dvec4(0.0, 0.0, 0.0, 1.0) + ); + _shaderProgram->setUniform(_uniformCache.eyePosition, eyePosition); - glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + glm::dvec3 cameraUp = data.camera.lookUpVectorWorldSpace(); + _shaderProgram->setUniform(_uniformCache.cameraUp, cameraUp); - _shaderProgram->setUniform(_uniformCache.modelViewTransform, modelViewTransform); + glm::dmat4 modelMatrix = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), data.modelTransform.scale); + _shaderProgram->setUniform(_uniformCache.modelMatrix, modelMatrix); + + glm::dmat4 projectionMatrix = glm::dmat4(data.camera.projectionMatrix()); + glm::dmat4 cameraViewProjectionMatrix = projectionMatrix * + data.camera.combinedViewMatrix(); _shaderProgram->setUniform( - _uniformCache.modelViewProjectionTransform, - glm::dmat4(data.camera.projectionMatrix()) * modelViewTransform + _uniformCache.cameraViewProjectionMatrix, + cameraViewProjectionMatrix ); _shaderProgram->setUniform(_uniformCache.color, _color); _shaderProgram->setUniform(_uniformCache.opacity, _opacity); _shaderProgram->setUniform(_uniformCache.size, _size); + _shaderProgram->setUniform(_uniformCache.sizeOption, _sizeOption); // Changes GL state: glEnablei(GL_BLEND, 0); - glDepthMask(false); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex + glDepthMask(false); glBindVertexArray(_vertexArrayObjectID); const GLsizei nPoints = static_cast(_fullData.size() / _nValuesPerPoint); @@ -295,7 +323,7 @@ void RenderablePointsCloud::createDataSlice() { } void RenderablePointsCloud::loadData() { - if (_pointData.empty() && !_dataStorageKey.has_value()) { + if (!_dataStorageKey.has_value()) { LWARNING("No point data found"); return; } @@ -303,25 +331,9 @@ void RenderablePointsCloud::loadData() { // @TODO: potentially combine point data with additional data about the points, // such as luminosity - if (!_pointData.empty()) { - int dataSize = static_cast(_pointData.size()); - std::vector values; - values.reserve(_nValuesPerPoint * _nPoints); - - for (int i = 0; i < dataSize; i++) { - for (int j = 0; j < _nValuesPerPoint; j++) { - values.push_back(_pointData[i][j]); - } - } - - _fullData.insert(_fullData.end(), values.begin(), values.end()); - } - else { - // Fetch data from module's centralized storage - auto module = global::moduleEngine->module(); - _fullData = module->fetchData(_dataStorageKey.value()); - _nPoints = _fullData.size(); - } + // Fetch data from module's centralized storage + auto module = global::moduleEngine->module(); + _fullData = module->fetchData(_dataStorageKey.value()); _isDirty = true; } diff --git a/modules/softwareintegration/rendering/renderablepointscloud.h b/modules/softwareintegration/rendering/renderablepointscloud.h index be39d7332b..d9c45e1333 100644 --- a/modules/softwareintegration/rendering/renderablepointscloud.h +++ b/modules/softwareintegration/rendering/renderablepointscloud.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -64,24 +65,28 @@ protected: bool _isDirty = true; std::unique_ptr _shaderProgram = nullptr; - UniformCache(modelViewTransform, modelViewProjectionTransform, - color, opacity, size) _uniformCache; + UniformCache(color, opacity, size, modelMatrix, cameraUp, + cameraViewProjectionMatrix, eyePosition, sizeOption) _uniformCache; properties::BoolProperty _isVisible; properties::FloatProperty _size; properties::Vec3Property _color; - - std::vector _pointData; + properties::OptionProperty _sizeOption; + std::vector _fullData; std::vector _slicedData; std::optional _dataStorageKey = std::nullopt; - int _nPoints = 0; // TODO: CHANGE TO size_t? int _nValuesPerPoint = 0; GLuint _vertexArrayObjectID = 0; GLuint _vertexBufferObjectID = 0; + + enum SizeOption { + Uniform = 0, + NonUniform = 1 + }; }; }// namespace openspace diff --git a/modules/softwareintegration/shaders/point_fs.glsl b/modules/softwareintegration/shaders/point_fs.glsl index 68951277b0..98e201dc25 100644 --- a/modules/softwareintegration/shaders/point_fs.glsl +++ b/modules/softwareintegration/shaders/point_fs.glsl @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2020 * + * Copyright (c) 2014-2022 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -25,27 +25,29 @@ #include "fragment.glsl" #include "PowerScaling/powerScaling_fs.hglsl" -in float vs_depthClipSpace; -in vec4 vs_positionViewSpace; +in vec2 coords; +flat in float ge_screenSpaceDepth; +in vec4 ge_positionViewSpace; uniform vec3 color; uniform float opacity; Fragment getFragment() { + if (opacity < 0.01) discard; - float radius = 0.5; - float distance = length(gl_PointCoord - vec2(radius)); + const float radius = 0.5; + float d = length(coords - radius); + if (d > 0.5) discard; - if (distance > pow(radius, 2)) - discard; + // calculate distance from the origin point + float circle = smoothstep(radius, radius - (radius * 0.3), d); Fragment frag; - frag.color = vec4(color, opacity); - frag.depth = vs_depthClipSpace; - frag.gPosition = vs_positionViewSpace; - - // There is no normal here - frag.gNormal = vec4(0.0, 0.0, -1.0, 1.0); + frag.color = vec4(color, opacity) * vec4(circle); + frag.depth = ge_screenSpaceDepth; + frag.gPosition = ge_positionViewSpace; + frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0); + frag.disableLDR2HDR = true; return frag; } diff --git a/modules/softwareintegration/shaders/point_ge.glsl b/modules/softwareintegration/shaders/point_ge.glsl new file mode 100644 index 0000000000..407d46fa2e --- /dev/null +++ b/modules/softwareintegration/shaders/point_ge.glsl @@ -0,0 +1,115 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScalingMath.hglsl" + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +flat out float ge_screenSpaceDepth; +out vec4 ge_positionViewSpace; + +out vec2 coords; + +uniform dvec3 eyePosition; +uniform dvec3 cameraUp; +uniform float size; +uniform int sizeOption; + +uniform dmat4 modelMatrix; +uniform dmat4 modelViewTransform; +uniform dmat4 cameraViewProjectionMatrix; + +// FRAGILE +// All of these values have to be synchronized with the values in the optionproperty +const int SizeCompositionOptionUniform = 0; +const int SizeCompositionOptionNonUniform = 1; + +double scaleForNonUniform() { + return (size * 500.0) * pow(10.0, 12.5); +} + +double scaleForUniform(vec3 pos) { + double distanceToPoint = length(eyePosition - pos); + + return (distanceToPoint * size) / (1500.0); +} + +void main() { + vec3 pos = gl_in[0].gl_Position.xyz; + + double scaleMultiply = 1.0; + if (sizeOption == SizeCompositionOptionUniform) { + scaleMultiply = scaleForUniform(pos); + } + else if (sizeOption == SizeCompositionOptionNonUniform) { + scaleMultiply = scaleForNonUniform(); + } + + dvec3 normal = normalize(eyePosition - pos); + dvec3 newRight = normalize(cross(cameraUp, normal)); + dvec3 newUp = normalize(cross(normal, newRight)); + dvec3 scaledRight = scaleMultiply * newRight; + dvec3 scaledUp = scaleMultiply * newUp; + + vec4 lowerLeft = z_normalization( + vec4(cameraViewProjectionMatrix * modelMatrix * dvec4(pos - scaledRight - scaledUp, 1.0)) + ); + + vec4 upperRight = z_normalization( + vec4(cameraViewProjectionMatrix * modelMatrix * dvec4(pos + scaledUp + scaledRight, 1.0)) + ); + + vec4 lowerRight = z_normalization( + vec4(cameraViewProjectionMatrix * modelMatrix * dvec4(pos + scaledRight - scaledUp, 1.0)) + ); + + vec4 upperLeft = z_normalization( + vec4(cameraViewProjectionMatrix * modelMatrix * dvec4(pos + scaledUp - scaledRight, 1.0)) + ); + + ge_screenSpaceDepth = lowerLeft.w; + ge_positionViewSpace = lowerLeft; + + // Build primitive + gl_Position = lowerLeft; + coords = vec2(0.0, 0.0); + EmitVertex(); + + gl_Position = lowerRight; + coords = vec2(1.0, 0.0); + EmitVertex(); + + gl_Position = upperLeft; + coords = vec2(0.0, 1.0); + EmitVertex(); + + gl_Position = upperRight; + coords = vec2(1.0, 1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/modules/softwareintegration/shaders/point_vs.glsl b/modules/softwareintegration/shaders/point_vs.glsl index 5dc9b5838b..607c518511 100644 --- a/modules/softwareintegration/shaders/point_vs.glsl +++ b/modules/softwareintegration/shaders/point_vs.glsl @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2020 * + * Copyright (c) 2014-2022 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -28,23 +28,6 @@ layout(location = 0) in vec3 in_position; -out float vs_depthClipSpace; -out vec4 vs_positionViewSpace; - -uniform dmat4 modelViewTransform; -uniform dmat4 MVPTransform; -uniform float size; - void main() { - dvec4 position = dvec4(in_position, 1.0); - dvec4 positionViewSpace = modelViewTransform * position; - dvec4 positionClipSpace = MVPTransform * position; - - positionClipSpace.z = 0.0; - - vs_depthClipSpace = float(positionClipSpace.w); - vs_positionViewSpace = vec4(positionViewSpace); - - gl_PointSize = size; - gl_Position = vec4(positionClipSpace); + gl_Position = vec4(in_position, 1.0); }