diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index cd891cdec9..dcd096bbb4 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -76,6 +76,7 @@ set(SHADER_FILES shaders/debrisVizPoints_gs.glsl shaders/debrisVizPoints_vs.glsl shaders/debrisVizTrails_fs.glsl + shaders/debrisVizTrails_gs.glsl shaders/debrisVizTrails_vs.glsl shaders/fluxnodes_fs.glsl shaders/fluxnodes_vs.glsl diff --git a/modules/space/rendering/renderableorbitalkepler.cpp b/modules/space/rendering/renderableorbitalkepler.cpp index a153ab88cb..f3362e1c0c 100644 --- a/modules/space/rendering/renderableorbitalkepler.cpp +++ b/modules/space/rendering/renderableorbitalkepler.cpp @@ -123,8 +123,9 @@ namespace { constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = { "TrailFade", - "Trail Fade Factor", - "Determines how fast the trail fades out.", + "Trail Fade", + "Determines how fast the trail fades out. A smaller number shows less of the " + "trail and a larger number shows more.", openspace::properties::Property::Visibility::User }; @@ -255,14 +256,14 @@ RenderableOrbitalKepler::Appearance::Appearance() }) , color(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) , trailWidth(TrailWidthInfo, 2.f, 1.f, 20.f) - , pointSizeExponent(PointSizeExponentInfo, 1.0f, 0.f, 25.f) + , pointSizeExponent(PointSizeExponentInfo, 1.0f, 0.f, 11.f) , renderingModes( RenderingModeInfo, properties::OptionProperty::DisplayType::Dropdown ) , trailFade(TrailFadeInfo, 20.f, 0.f, 30.f) - , enableMaxSize(EnableMaxSizeInfo, false) - , maxSize(MaxSizeInfo, 1.f, 0.f, 45.f) + , enableMaxSize(EnableMaxSizeInfo, true) + , maxSize(MaxSizeInfo, 5.f, 0.f, 45.f) , enableOutline(EnableOutlineInfo, true) , outlineColor(OutlineColorInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f)) , outlineWidth(OutlineWidthInfo, 0.2f, 0.f, 1.f) @@ -378,7 +379,8 @@ void RenderableOrbitalKepler::initializeGL() { return global::renderEngine->buildRenderProgram( "OrbitalKeplerTrails", absPath("${MODULE_SPACE}/shaders/debrisVizTrails_vs.glsl"), - absPath("${MODULE_SPACE}/shaders/debrisVizTrails_fs.glsl") + absPath("${MODULE_SPACE}/shaders/debrisVizTrails_fs.glsl"), + absPath("${MODULE_SPACE}/shaders/debrisVizTrails_gs.glsl") ); } ); @@ -401,7 +403,10 @@ void RenderableOrbitalKepler::initializeGL() { _trailProgram->uniformLocation("modelViewTransform"); _uniformTrailCache.projection = _trailProgram->uniformLocation("projectionTransform"); - _uniformTrailCache.trailFade = _trailProgram->uniformLocation("trailFade"); + _uniformTrailCache.colorFadeCutoffValue = + _trailProgram->uniformLocation("colorFadeCutoffValue"); + _uniformTrailCache.trailFadeExponent = + _trailProgram->uniformLocation("trailFadeExponent"); _uniformTrailCache.inGameTime = _trailProgram->uniformLocation("inGameTime"); _uniformTrailCache.color = _trailProgram->uniformLocation("color"); _uniformTrailCache.opacity = _trailProgram->uniformLocation("opacity"); @@ -562,7 +567,14 @@ void RenderableOrbitalKepler::render(const RenderData& data, RendererTasks&) { const float fade = pow( _appearance.trailFade.maxValue() - _appearance.trailFade, 2.f ); - _trailProgram->setUniform(_uniformTrailCache.trailFade, fade); + _trailProgram->setUniform(_uniformTrailCache.trailFadeExponent, fade); + + // 0.05 is the "alpha value" for which the trail should no longer be rendered. + // The value that's compared to 0.05 is calculated in the shader and depends + // on the distance from the head of the trail to the part that's being rendered. + // Value is passed as uniform due to it being used in both geometry and fragment + // shader. + _trailProgram->setUniform(_uniformTrailCache.colorFadeCutoffValue, 0.05f); glLineWidth(_appearance.trailWidth); diff --git a/modules/space/rendering/renderableorbitalkepler.h b/modules/space/rendering/renderableorbitalkepler.h index 0220424489..d404806640 100644 --- a/modules/space/rendering/renderableorbitalkepler.h +++ b/modules/space/rendering/renderableorbitalkepler.h @@ -112,7 +112,8 @@ private: RenderableOrbitalKepler::Appearance _appearance; // Line cache - UniformCache(modelView, projection, trailFade, inGameTime, color, opacity) + UniformCache(modelView, projection, trailFadeExponent, colorFadeCutoffValue, + inGameTime, color, opacity) _uniformTrailCache; // Point cache @@ -126,4 +127,3 @@ private: } // namespace openspace #endif // __OPENSPACE_MODULE_SPACE___RENDERABLEORBITALKEPLER___H__ - diff --git a/modules/space/shaders/debrisVizPoints_fs.glsl b/modules/space/shaders/debrisVizPoints_fs.glsl index 51e7f339fe..2ad062d058 100644 --- a/modules/space/shaders/debrisVizPoints_fs.glsl +++ b/modules/space/shaders/debrisVizPoints_fs.glsl @@ -27,7 +27,6 @@ in float projectionViewDepth; in vec4 viewSpace; in vec2 texCoord; -flat in int skip; uniform bool enableOutline; uniform vec3 outlineColor; @@ -38,10 +37,6 @@ uniform float opacity; Fragment getFragment() { Fragment frag; - if (skip == 1) { - discard; - } - // Only draw circle instead of entire quad vec2 st = (texCoord - vec2(0.5)) * 2.0; if (length(st) > 1.0) { diff --git a/modules/space/shaders/debrisVizPoints_gs.glsl b/modules/space/shaders/debrisVizPoints_gs.glsl index c477d3b349..fb50433753 100644 --- a/modules/space/shaders/debrisVizPoints_gs.glsl +++ b/modules/space/shaders/debrisVizPoints_gs.glsl @@ -27,8 +27,8 @@ #include "PowerScaling/powerScalingMath.hglsl" layout(lines) in; -flat in double currentRevolutionFraction[]; -flat in double vertexRevolutionFraction[]; +flat in float currentRevolutionFraction[]; +flat in float vertexRevolutionFraction[]; uniform dmat4 modelTransform; uniform dmat4 viewTransform; @@ -43,103 +43,95 @@ layout(triangle_strip, max_vertices = 4) out; out float projectionViewDepth; out vec4 viewSpace; out vec2 texCoord; -flat out int skip; - -dvec4 dz_normalization(dvec4 dv_in) { - dvec4 dv_out = dv_in; - dv_out.z = 0; - return dv_out; -} void main() { - skip = 0; - - double cFrac = currentRevolutionFraction[0]; - double v0Frac = vertexRevolutionFraction[0]; - double v1Frac = vertexRevolutionFraction[1]; + // cFrac is how far along the trail orbit the head of the trail is. + // v0Frac and v1Frac are how far the two vertices that creates the current line strip + // are along the trail orbit. The variables span between 0 and 1, where 0 is the + // beginning of the trail and 1 is the end of the trail (a full orbit). + float cFrac = currentRevolutionFraction[0]; + float v0Frac = vertexRevolutionFraction[0]; + float v1Frac = vertexRevolutionFraction[1]; + + // Only create/emit vertices for segments where the head of the trail falls within if (cFrac >= v0Frac && cFrac <= v1Frac) { - // Interpolate position of point - double dFrac = abs(cFrac - v0Frac); - double vFrac = abs(v1Frac - v0Frac); - double percentage = dFrac / vFrac; - - dvec4 v0Weighted = (1.0 - percentage) * gl_in[0].gl_Position; - dvec4 v1Weighted = (percentage) * gl_in[1].gl_Position; - - dvec4 pos = v0Weighted + v1Weighted; + // Interpolate position of current position of the trail head + float dFrac = abs(cFrac - v0Frac); + float vFrac = abs(v1Frac - v0Frac); + float percentage = dFrac / vFrac; + + vec4 v0Weighted = (1.0 - percentage) * gl_in[0].gl_Position; + vec4 v1Weighted = (percentage) * gl_in[1].gl_Position; + vec4 pos = v0Weighted + v1Weighted; // ========================== + // Cast to float based data types + mat4 modelTrans = mat4(modelTransform); + mat4 viewTrans = mat4(viewTransform); + vec3 camPosWorld = vec3(cameraPositionWorld); + // Calculate current vertex position to world space - dvec4 vertPosWorldSpace = modelTransform * pos; + vec4 vertPosWorldSpace = modelTrans * pos; // Calculate new axis for plane - dvec3 normal = normalize(cameraPositionWorld - vertPosWorldSpace.xyz); - dvec3 right = normalize(cross(cameraUpWorld, normal)); - dvec3 up = normalize(cross(normal, right)); + vec3 normal = vec3(normalize(camPosWorld - vertPosWorldSpace.xyz)); + vec3 right = normalize(cross(vec3(cameraUpWorld), normal)); + vec3 up = normalize(cross(normal, right)); // Calculate size of points - double initialSize = pow(10.0, pointSizeExponent); + float initialSize = pow(10.0, pointSizeExponent); right *= initialSize; up *= initialSize; - double opp = length(right); - double adj = length(cameraPositionWorld.xyz - vertPosWorldSpace.xyz); + float opp = length(right); + float adj = length(camPosWorld - vertPosWorldSpace.xyz); float angle = atan(float(opp/adj)); float maxAngle = radians(maxSize * 0.5); // Controls the point size if (enableMaxSize && (angle > maxAngle) && (adj > 0.0)) { - double correction = (adj * tan(maxAngle)) / opp; + float correction = (adj * tan(maxAngle)) / opp; right *= correction; up *= correction; } - // Calculate and set corners of the quad - dvec4 p0World = vertPosWorldSpace + (dvec4(up-right, 0.0)); - dvec4 p1World = vertPosWorldSpace + (dvec4(-right-up,0.0)); - dvec4 p2World = vertPosWorldSpace + (dvec4(right+up, 0.0)); - dvec4 p3World = vertPosWorldSpace + (dvec4(right-up, 0.0)); + // Calculate and set corners of the new quad + vec4 p0World = vertPosWorldSpace + vec4(up-right, 0.0); + vec4 p1World = vertPosWorldSpace + vec4(-right-up,0.0); + vec4 p2World = vertPosWorldSpace + vec4(right+up, 0.0); + vec4 p3World = vertPosWorldSpace + vec4(right-up, 0.0); - dmat4 ViewProjectionTransform = dmat4(projectionTransform) * viewTransform; + mat4 ViewProjectionTransform = projectionTransform * viewTrans; // Set some additional out parameters - viewSpace = z_normalization( - vec4(projectionTransform * viewTransform * modelTransform * pos) - ); + viewSpace = z_normalization(projectionTransform * viewTrans * modelTrans * pos); projectionViewDepth = viewSpace.w; - //left-top - vec4 p0Screen = vec4(dz_normalization(ViewProjectionTransform * p0World)); + // left-top + vec4 p0Screen = z_normalization(ViewProjectionTransform * p0World); gl_Position = p0Screen; texCoord = vec2(0.0, 0.0); EmitVertex(); - //left-bot - vec4 p1Screen = vec4(dz_normalization(ViewProjectionTransform * p1World)); + // left-bot + vec4 p1Screen = z_normalization(ViewProjectionTransform * p1World); gl_Position = p1Screen; texCoord = vec2(1.0, 0.0); EmitVertex(); - //right-top - vec4 p2Screen = vec4(dz_normalization(ViewProjectionTransform * p2World)); + // right-top + vec4 p2Screen = z_normalization(ViewProjectionTransform * p2World); gl_Position = p2Screen; texCoord = vec2(0.0, 1.0); EmitVertex(); - //right-bot - vec4 p3Screen = vec4(dz_normalization(ViewProjectionTransform * p3World)); + // right-bot + vec4 p3Screen = z_normalization(ViewProjectionTransform * p3World); gl_Position = p3Screen; texCoord = vec2(1.0, 1.0); EmitVertex(); - - // Primitive - EndPrimitive(); - } - else { - skip = 1; - EmitVertex(); - EndPrimitive(); - } + + EndPrimitive(); } diff --git a/modules/space/shaders/debrisVizPoints_vs.glsl b/modules/space/shaders/debrisVizPoints_vs.glsl index 4d0c23ac5b..97b0e8e6af 100644 --- a/modules/space/shaders/debrisVizPoints_vs.glsl +++ b/modules/space/shaders/debrisVizPoints_vs.glsl @@ -28,21 +28,24 @@ layout (location = 0) in vec4 vertexData; // 1: x, 2: y, 3: z, 4: timeOffset, layout (location = 1) in vec2 orbitData; // 1: epoch, 2: period uniform double inGameTime; -uniform dmat4 modelTransform; -flat out double currentRevolutionFraction; -flat out double vertexRevolutionFraction; +flat out float currentRevolutionFraction; +flat out float vertexRevolutionFraction; void main() { float epoch = orbitData.x; float period = orbitData.y; - double numOfRevolutions = (inGameTime - epoch) / period; - vertexRevolutionFraction = vertexData.w / period; - currentRevolutionFraction = numOfRevolutions - double(int(numOfRevolutions)); + // calculate nr of periods, get fractional part to know where the vertex closest to the + // debris part is right now + double numOfRevolutions = (inGameTime - epoch) / period; + currentRevolutionFraction = float(numOfRevolutions - double(int(numOfRevolutions))); if (currentRevolutionFraction < 0.0) { currentRevolutionFraction += 1.0; } + // Same procedure for the current vertex + vertexRevolutionFraction = vertexData.w / period; + gl_Position = vec4(vertexData.xyz, 1.0); } diff --git a/modules/space/shaders/debrisVizTrails_fs.glsl b/modules/space/shaders/debrisVizTrails_fs.glsl index 39e7af9289..aa1a1377e6 100644 --- a/modules/space/shaders/debrisVizTrails_fs.glsl +++ b/modules/space/shaders/debrisVizTrails_fs.glsl @@ -31,18 +31,11 @@ in float offsetPeriods; uniform vec3 color; uniform float opacity = 1.0; -uniform float trailFade; - -/// Different modes - sync with renderableorbitalkepler.cpp -// RenderingModeLines = 0 -// RenderingModePoint = 1 +uniform float trailFadeExponent; +uniform float colorFadeCutoffValue; Fragment getFragment() { Fragment frag; - - float invert = 1.0; - float fade = 1.0; - // float offsetPeriods = offset / period; // This is now done in the fragment shader instead to make smooth movement between // vertices. We want vertexDistance to be double up to this point, I think, (hence the @@ -58,15 +51,15 @@ Fragment getFragment() { vertexDistance += 1.0; } - invert = pow((1.0 - vertexDistance), trailFade); - fade = clamp(invert, 0.0, 1.0); + float invert = pow((1.0 - vertexDistance), trailFadeExponent); + float fade = clamp(invert, 0.0, 1.0); // Currently even fully transparent lines can occlude other lines, thus we discard these // fragments since debris and satellites are rendered so close to each other - if (fade < 0.05) { + if (fade < colorFadeCutoffValue) { discard; } - + // Use additive blending for some values to make the discarding less abrupt if (fade < 0.15) { frag.blend = BLEND_MODE_ADDITIVE; diff --git a/modules/space/shaders/debrisVizTrails_gs.glsl b/modules/space/shaders/debrisVizTrails_gs.glsl new file mode 100644 index 0000000000..f098d79d18 --- /dev/null +++ b/modules/space/shaders/debrisVizTrails_gs.glsl @@ -0,0 +1,85 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2024 * + * * + * 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__ + +layout(lines) in; +flat in float currentRevolutionFraction[]; +flat in float vertexRevolutionFraction[]; +flat in vec4 viewSpacePositions[]; + +layout(line_strip, max_vertices = 2) out; +out float viewSpaceDepth; +out float periodFraction; +out float offsetPeriods; +out vec4 viewSpacePosition; + +uniform float trailFadeExponent; +uniform float colorFadeCutoffValue; + +void main() { + // cFrac is how far along the trail orbit the head of the trail is. + // v0Frac and v1Frac are how far the two vertices that creates the current line strip + // are along the trail orbit. The variables span between 0 and 1, where 0 is the + // beginning of the trail and 1 is the end of the trail (a full orbit). + float cFrac = currentRevolutionFraction[0]; + float v0Frac = vertexRevolutionFraction[0]; + float v1Frac = vertexRevolutionFraction[1]; + + // Distance between current revolution fraction and revolution fraction for + // vertex0 and vertex1 + float vd0 = cFrac - v0Frac; + if (vd0 < 0.0) { + vd0 += 1.0; + } + + float vd1 = cFrac - v1Frac; + if (vd1 < 0.0) { + vd1 += 1.0; + } + // ========================== + + // Calculates if vertex0 is close enough to NOT be discarded in fragment shader + float invert = pow(1.0 - vd1, trailFadeExponent); + float fade = clamp(invert, 0.0, 1.0); + + // Only emit vertices for line segments where both vertices should be rendered + if ((fade > colorFadeCutoffValue) || (vd0 < vd1)) { + gl_Position = gl_in[0].gl_Position; + viewSpaceDepth = gl_Position.w; + periodFraction = cFrac; + offsetPeriods = v0Frac; + viewSpacePosition = viewSpacePositions[0]; + EmitVertex(); + + gl_Position = gl_in[1].gl_Position; + viewSpaceDepth = gl_Position.w; + periodFraction = cFrac; + offsetPeriods = v1Frac; + viewSpacePosition = viewSpacePositions[1]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/modules/space/shaders/debrisVizTrails_vs.glsl b/modules/space/shaders/debrisVizTrails_vs.glsl index 472be3ca12..3b0c7ce92a 100644 --- a/modules/space/shaders/debrisVizTrails_vs.glsl +++ b/modules/space/shaders/debrisVizTrails_vs.glsl @@ -29,10 +29,9 @@ layout (location = 0) in vec4 vertexData; // 1: x, 2: y, 3: z, 4: timeOffset, layout (location = 1) in vec2 orbitData; // 1: epoch, 2: period -out vec4 viewSpacePosition; -out float viewSpaceDepth; -out float periodFraction; -out float offsetPeriods; +flat out float currentRevolutionFraction; +flat out float vertexRevolutionFraction; +flat out vec4 viewSpacePositions; uniform dmat4 modelViewTransform; uniform mat4 projectionTransform; @@ -54,18 +53,15 @@ void main() { // calculate nr of periods, get fractional part to know where the vertex closest to the // debris part is right now double nrOfRevolutions = (inGameTime - epoch) / period; - double frac = double(int(nrOfRevolutions)); - double periodFractiond = nrOfRevolutions - frac; - if (periodFractiond < 0.0) { - periodFractiond += 1.0; - } - periodFraction = float(periodFractiond); + currentRevolutionFraction = float(nrOfRevolutions - double(int(nrOfRevolutions))); + if (currentRevolutionFraction < 0.0) { + currentRevolutionFraction += 1.0; + } - // same procedure for the current vertex - offsetPeriods = vertexData.w / float(period); - - viewSpacePosition = vec4(modelViewTransform * dvec4(vertexData.xyz, 1)); - vec4 vs_position = z_normalization(projectionTransform * viewSpacePosition); + // Same procedure for the current vertex + vertexRevolutionFraction = vertexData.w / period; + + viewSpacePositions = vec4(modelViewTransform * dvec4(vertexData.xyz, 1)); + vec4 vs_position = z_normalization(projectionTransform * viewSpacePositions); gl_Position = vs_position; - viewSpaceDepth = vs_position.w; }