Optimization of point and trail rendering (#3287)

Better performance for `RenderableOrbitalKepler` when running `Trails`, `Points` or `Points+Trails`.
Trails optimized by culling non-visible line strips.
Points optimized by changing a lot of calculations from double to float.
This commit is contained in:
Adam Rohdin
2024-06-04 18:37:04 +02:00
committed by GitHub
parent 1cae99ebfc
commit 945a9a5ca8
9 changed files with 184 additions and 107 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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__

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;
}