Merge branch 'master' into feature/animation-fixes

This commit is contained in:
Malin E
2021-10-25 10:51:13 +02:00
73 changed files with 5077 additions and 916 deletions

View File

@@ -1,6 +1,8 @@
local transforms = asset.require('scene/solarsystem/planets/earth/transforms')
local debugHelper = asset.require('util/debug_helper')
local sun_transforms = asset.require('scene/solarsystem/sun/transforms')
local sunRadius = 6.957E8
local earthRadius = 6.371E6
debugHelper.registerCartesianAxes(asset, {
@@ -17,3 +19,13 @@ debugHelper.registerCartesianAxes(asset, {
Parent = transforms.EarthIAU.Identifier,
Scale = earthRadius * 1.5
})
debugHelper.registerCartesianAxes(asset, {
Parent = sun_transforms.SunIAU.Identifier,
Scale = sunRadius * 300
})
debugHelper.registerCartesianAxes(asset, {
Parent = sun_transforms.SolarSystemBarycenter.Identifier,
Scale = sunRadius * 300
})

View File

@@ -0,0 +1,16 @@
local CarringtonLongitudeToHEEQ180Rotation = {
-- This is a rotation matrix to go from Carrington longitude referens frame to HEEQ180
-- reference fram. At the reference time, MAS_seq = 0, 2000-07-14T08:33:37.105 the
-- Carrington longitude was 309.3 degrees.
-- Difference from HEEQ => 360-309.3=50.7
-- (or 0-309.3 = -309.3 However this leads to the same rotation matrix in the end)
-- Since OpenSpace supports HEEQ180 and not HEEQ, 180 was added or subtracted
-- => a1 = -129.3 and a2 = 230.7
-- Rotation matrix: (cos a, -sin a, 0)(sin a, cos a, 0)(0, 0, 1) leads to the result.
Type = "FixedRotation",
XAxis = { -0.63338087262755016203262119192353, -0.77384020972650618518999944537717, 0.0 },
YAxis = { 0.77384020972650618518999944537717, -0.63338087262755016203262119192353, 0.0 },
ZAxis = { 0.0, 0.0, 1.0 }
}
asset.export("CarringtonLongitudeToHEEQ180Rotation", CarringtonLongitudeToHEEQ180Rotation)

View File

@@ -0,0 +1,73 @@
local assetHelper = asset.require("util/asset_helper")
local propertyHelper = asset.require('util/property_helper')
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
local densityDirectory = asset.syncedResource({
Name = "Bastille Day MAS Density",
Type = "HttpSynchronization",
Identifier = "bastille_day_mas_density",
Version = 1
})
local sunRadius = 6.957E8
local densityVolume = {
Identifier = "MAS-MHD-Density-bastille-day-2000",
Parent = sunTransforms.SunIAU.Identifier,
Transform = {
Scale = {
Type = "StaticScale",
Scale = sunRadius
},
Rotation = {
Type = "FixedRotation",
XAxis = { -1.0, 0.0, 0.0 },
YAxis = { 0.0, 1.0, 0.0 },
ZAxis = { 0.0, 0.0, -1.0 }
}
},
Renderable = {
Type = "RenderableTimeVaryingVolume",
StepSize = 0.004,
Opacity = 0.3,
TransferFunction = asset.localResource("transferfunctions/mas-mhd-r-squared-old.txt"),
SourceDirectory = densityDirectory,
GridType = "Spherical",
SecondsBefore = 24*60*60,
SecondsAfter = 24*60*60,
Dimensions = { 100, 100, 128 },
InvertDataAtZ = true
},
GUI = {
Name = "MAS Density",
Path = "/Solar System/Heliosphere/Bastille Day 2000",
Description = "Volumetric rendering for the bastille day CME event. This asset contain data from 2000-07-14 08:33 to 2000-07-14 11:49"
}
}
local toggle_volume = {
Identifier = "density_volume.toggle_volume",
Name = "Toggle volume",
Command = propertyHelper.invert("Scene.MAS-MHD-Density-bastille-day-2000.Renderable.Enabled"),
Documentation = "Toggle volume rendering of CME",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function ()
openspace.action.registerAction(toggle_volume)
end)
asset.onDeinitialize(function ()
openspace.action.removeAction(toggle_volume.Identifier)
end)
assetHelper.registerSceneGraphNodesAndExport(asset, { densityVolume })
asset.meta = {
Name = "Predictive Science Inc. Volume Rendering Bastille Day",
Version = "1.0",
Description = [[Volumetric rendering for the bastille day CME event]],
Author = "CCMC, OpenSpace team",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "CC-BY",
Identifier = {"MAS-MHD-Density-bastille-day-2000"}
}

View File

@@ -0,0 +1,76 @@
local assetHelper = asset.require('util/asset_helper')
local heliosphereTransforms = asset.require('scene/solarsystem/sun/transforms_heliosphere')
local propertyHelper = asset.require('util/property_helper')
local rot = asset.require('./carringtonToHEEQRotation.asset')
local fieldlinesDirectory = asset.syncedResource({
Name = "Bastille Day MAS Fieldlines",
Type = "HttpSynchronization",
Identifier = "bastille_day_mas_fieldlines",
Version = 1
})
local sunRadius = 6.957E8
-- Fieldlies from binaries
local fieldlines = {
Identifier = "MAS-MHD-Fieldlines-bastille-day-2000",
Parent = heliosphereTransforms.HEEQ180ReferenceFrame.Identifier,
Transform = {
Scale = {
Type = "StaticScale",
Scale = sunRadius
},
Rotation = rot.CarringtonLongitudeToHEEQ180Rotation
},
Renderable = {
Type = "RenderableFieldlinesSequence",
SourceFolder = fieldlinesDirectory,
AlphaBlendlingEnabled = false,
InputFileType = "Osfls",
ColorTablePaths = {
asset.localResource("transferfunctions/density-fieldlines.txt"),
asset.localResource("transferfunctions/velocity-fieldlines.txt")
},
ColorTableMinMax = {
{ 0, 1000000 },
{ 100, 2000 }
},
SimulationModel = "mas",
Color = {
Uniform = { 0.0, 0.725, 0.75, 1.0 }
}
},
GUI = {
Path = "/Solar System/Heliosphere/Bastille Day 2000",
Name = "MAS Fieldlines",
Description = "Magnetic fieldlines for the bastille day CME event. This asset contains data from 2000-07-14 08:33 to 2000-07-14 11:49"
}
}
local toggle_fieldlines = {
Identifier = "fieldlines.toggle_fieldlines",
Name = "Toggle Fieldlines",
Command = propertyHelper.invert("Scene.MAS-MHD-Fieldlines-bastille-day-2000.Renderable.Enabled"),
Documentation = "Toggle fieldline rendering of CME",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function ()
openspace.action.registerAction(toggle_fieldlines)
end)
asset.onDeinitialize(function ()
openspace.action.removeAction(toggle_fieldlines.Identifier)
end)
assetHelper.registerSceneGraphNodesAndExport(asset, { fieldlines })
asset.meta = {
Name = "Predictive Science Inc. Fieldlines Bastille Day",
Version = "1.0",
Description = [[Magnetic fieldlines for the bastille day CME event]],
Author = "CCMC, Jonathan Grangien, Matthias Berg",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "CC-BY",
Identifier = {"MAS-MHD-Fieldlines-bastille-day-2000"}
}

View File

@@ -0,0 +1,58 @@
local assetHelper = asset.require('util/asset_helper')
local heliosphereTransforms = asset.require('scene/solarsystem/sun/transforms_heliosphere')
local propertyHelper = asset.require('util/property_helper')
local rot = asset.require('./carringtonToHEEQRotation.asset')
local fluxNodesBinaries = asset.syncedResource({
Name = "Bastille day Flux nodes binaries",
Type = "HttpSynchronization",
Identifier = "bastille_day_streamnodes_binaries",
Version = 1
})
-- FluxNodes from binaries
local fluxNodes = {
Identifier = "MAS-MHD-FluxNodes-bastille-day-2000",
Parent = heliosphereTransforms.HEEQ180ReferenceFrame.Identifier,
Transform = {
Rotation = rot.CarringtonLongitudeToHEEQ180Rotation
},
Renderable = {
Type = "RenderableFluxNodes",
SourceFolder = fluxNodesBinaries,
ColorTablePath = asset.localResource("transferfunctions/CMR.txt"),
ColorTableRange = {-2.0, 4.0}
},
GUI = {
Path = "/Solar System/Heliosphere/Bastille Day 2000",
Name = "Flux Nodes",
Description = "Flux nodes for the bastille day CME event. This asset contains data from 2000-07-14 08:38 to 2000-07-14 19:48"
}
}
local toggle_fluxnodes = {
Identifier = "fluxnodes.toggle_fluxnodes",
Name = "Toggle flux nodes",
Command = propertyHelper.invert("Scene.MAS-MHD-FluxNodes-bastille-day-2000.Renderable.Enabled"),
Documentation = "Toggle flux node rendering of CME",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function ()
openspace.action.registerAction(toggle_fluxnodes)
end)
asset.onDeinitialize(function ()
openspace.action.removeAction(toggle_fluxnodes.Identifier)
end)
assetHelper.registerSceneGraphNodesAndExport(asset, { fluxNodes })
asset.meta = {
Name = "Predictive Science Inc. Flux nodes Bastille Day",
Version = "1.0",
Description = [[Flux nodes for the bastille day CME event]],
Author = "CCMC, Christian Adamsson, Emilie Ho",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "CC-BY",
Identifier = {"MAS-MHD-FluxNodes-bastille-day-2000"}
}

View File

@@ -0,0 +1,102 @@
local assetHelper = asset.require("util/asset_helper")
local propertyHelper = asset.require("util/property_helper")
local transforms = asset.require('scene/solarsystem/sun/transforms_heliosphere')
local rot = asset.require('./carringtonToHEEQRotation.asset')
local TexturesPathEquitorial = asset.syncedResource({
Type = "HttpSynchronization",
Name = "cutplanes_textures",
Identifier = "cutplanes_textures",
Version = 1
})
local TexturesPathMeridial = asset.syncedResource({
Type = "HttpSynchronization",
Name = "cutplane_meridial_textures",
Identifier = "cutplane_meridial_textures",
Version = 1
})
local EquatorialCutplane = {
Identifier = "EquatorialCutplane-bastille-day-2000",
Parent = transforms.HEEQ180ReferenceFrame.Identifier,
Transform = {
Rotation = rot.CarringtonLongitudeToHEEQ180Rotation
},
Renderable = {
Type = "RenderablePlaneTimeVaryingImage",
Size = 1.57E11,
Enabled = true,
SourceFolder = TexturesPathEquitorial,
BlendMode = "Normal",
MirrorBackside = false,
Opacity = 0.7
},
GUI = {
Name = "Cutplane Equitorial",
Path = "/Solar System/Heliosphere/Bastille Day 2000",
Description = "Equatorial cutplane sequence for the bastille day CME event. This asset contains data from 2000-07-14 08:38 to 2000-07-14 12:00"
}
}
local MeridialCutplane = {
Identifier = "MeridialCutplane-bastille-day-2000",
Parent = transforms.HEEQ180ReferenceFrame.Identifier,
Transform = {
Rotation = {
Type = "StaticRotation",
Rotation = { -math.pi/2, -math.pi, 0.0 }
}
},
Renderable = {
Type = "RenderablePlaneTimeVaryingImage",
Size = 1.57E11,
Enabled = true,
SourceFolder = TexturesPathMeridial,
BlendMode = "Normal",
MirrorBackside = false,
Opacity = 0.7
},
GUI = {
Name = "Cutplane Meridial",
Path = "/Solar System/Heliosphere/Bastille Day 2000",
Description = "Meridial cutplane sequence for the bastille day CME event. This asset contains data from 2000-07-14 08:38 to 2000-07-14 12:00"
}
}
local toggle_equatorial = {
Identifier = "fluxnodescutplane.toggle_equatorial",
Name = "Toggle equatorial cutplane",
Command = propertyHelper.invert("Scene.EquatorialCutplane-bastille-day-2000.Renderable.Enabled"),
Documentation = "Toggle equatorial cutplane of CME",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
local toggle_meridial = {
Identifier = "fluxnodescutplane.toggle_meridial",
Name = "Toggle meridial cutplane",
Command = propertyHelper.invert("Scene.MeridialCutplane-bastille-day-2000.Renderable.Enabled"),
Documentation = "Toggle meridial cutplane of CME",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function ()
openspace.action.registerAction(toggle_equatorial)
openspace.action.registerAction(toggle_meridial)
end)
asset.onDeinitialize(function ()
openspace.action.removeAction(toggle_equatorial.Identifier)
openspace.action.removeAction(toggle_meridial.Identifier)
end)
assetHelper.registerSceneGraphNodesAndExport(asset, { EquatorialCutplane, MeridialCutplane})
asset.meta = {
Name = "Predictive Science Inc. Cutplanes Bastille Days",
Version = "1.0",
Description = [[Cutplanes for the bastille day CME event]],
Author = "CCMC, Christian Adamsson, Emilie Ho",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "CC-BY",
Identifier = {"MeridialCutplane-bastille-day-2000", "EquatorialCutplane-bastille-day-2000"}
}

View File

@@ -0,0 +1,60 @@
asset.require("spice/base")
local assetHelper = asset.require("util/asset_helper")
local TexturesPath = asset.syncedResource({
Type = "HttpSynchronization",
Name = "Streamnodes textures",
Identifier = "streamnodes_legend",
Version = 1
})
local legend = {
Identifier = "LegendFluxNodes-bastille-day-2000",
Type = "ScreenSpaceImageLocal",
TexturePath = TexturesPath .. "/CMR_transparent_white_text.png",
Scale = 0.15,
CartesianPosition = { 0.677970, 0.0, -1.049180 }
}
local show_legend = {
Identifier = "fluxnodelegend.show_legend",
Name = "Show the legend image",
Command = "openspace.setPropertyValueSingle('ScreenSpace.LegendFluxNodes-bastille-day-2000.Opacity', 0.0);" ..
"openspace.setPropertyValueSingle('ScreenSpace.LegendFluxNodes-bastille-day-2000.Enabled', true);" ..
"openspace.setPropertyValueSingle('ScreenSpace.LegendFluxNodes-bastille-day-2000.Opacity', 1.0, 4);",
Documentation = "Show the legend image",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
local hide_legend = {
Identifier = "fluxnodelegend.hide_legend",
Name = "Hides the legend image",
Command = "openspace.setPropertyValueSingle('ScreenSpace.LegendFluxNodes-bastille-day-2000.Opacity', 0.0, 2);",
Documentation = "Hides the legend image",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function()
openspace.addScreenSpaceRenderable(legend)
-- These numbers are there to put the legend on the side of the screen.
openspace.setPropertyValueSingle('ScreenSpace.LegendFluxNodes-bastille-day-2000.Rotation', { 0.0, 0.0, 0.56652 });
openspace.action.registerAction(show_legend)
openspace.action.registerAction(hide_legend)
end)
asset.onDeinitialize(function ()
openspace.removeScreenSpaceRenderable(legend.Identifier)
openspace.action.removeAction(show_legend.Identifier)
openspace.action.removeAction(hide_legend.Identifier)
end)
asset.meta = {
Name = "Predictive Science Inc. Flux nodes legend for Bastille Days",
Version = "1.0",
Description = [[Screen space renderable image legend of flux nodes for the bastille day CME event]],
Author = "Christian Adamsson, Emilie Ho",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "MIT",
Identifier = {"LegendFluxNodes-bastille-day-2000"}
}

View File

@@ -0,0 +1,40 @@
local assetHelper = asset.require('util/asset_helper')
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
local earthTransforms = asset.require('scene/solarsystem/planets/earth/transforms')
local travelSpeedIndicator = {
Identifier = "TravelSpeedIndicator-2000",
--SunIAU adds an extra rotation. Using barycenter, then offsetting to SunIAU
Parent = sunTransforms.SolarSystemBarycenter.Identifier,
Transform = {
Translation = {
Type = "SpiceTranslation",
Target = "SUN",
Observer = "SSB"
}
},
Renderable = {
Type = "RenderableTravelSpeed",
Target = earthTransforms.EarthCenter.Identifier, --name of scene graph node. Earth by default
LineWidth = 4,
IndicatorLength = 10,
FadeLength = 10
},
GUI = {
Path = "/Solar System/Heliosphere",
Name = "Speed indicator",
Description = "Speed of light indicator from sun to earth"
}
}
assetHelper.registerSceneGraphNodesAndExport(asset, { travelSpeedIndicator })
asset.meta = {
Name = "Light travel from sun to earth",
Version = "1.0",
Description = [[Speed of light indicator from sun to earth]],
Author = "CCMC, Christian Adamsson, Emilie Ho",
URL = "",
License = "MIT",
Identifier = {"TravelSpeedIndicator-2000"}
}

View File

@@ -0,0 +1,22 @@
local TexturesPath = asset.syncedResource({
Name = "Bastille Day Magnetogram",
Type = "HttpSynchronization",
Identifier = "bastille_day_magnetogram",
Version = 5
})
asset.export("TexturesPath", TexturesPath)
-- Torok, T., Downs, C., Linker, J. A., Lionello, R., Titov, V. S., Mikic, Z., Riley, P., Caplan, R. M., and Wijaya, J. (2018).
-- Sun-to-Earth MHD Simulation of the 2000 July 14 Bastille Day Eruption.
-- ApJ,
-- 856:75.
asset.meta = {
Name = "Predictive Science Inc. MAS Bastille Day Textures",
Version = "1.0",
Description = [[Magnetograms of the sun as texture color layers]],
Author = "Jonathan Grangien, Matthias Berg",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "CC-BY",
Identifier = {"Sun"}
}

View File

@@ -0,0 +1,60 @@
local assetHelper = asset.require('util/asset_helper')
local sun = asset.require('scene/solarsystem/sun/sun')
-- synced directories
local magnetogramDirectory = asset.require('./magnetogram').TexturesPath;
local magnetograms;
local switch_color_layer = {
Identifier = "magnetogram_texture.switch_color_layer",
Name = "Next sun texture",
Command = [[
local textureList = openspace.globebrowsing.getLayers('Sun', 'ColorLayers');
if (magnetogramsTextureIndex == -1) then
magnetogramsTextureIndex = 2;
end;
magnetogramsTextureIndex = magnetogramsTextureIndex + 1;
if (magnetogramsTextureIndex >= #textureList) then
magnetogramsTextureIndex = 0;
end
openspace.setPropertyValue("Scene.Sun.Renderable.Layers.ColorLayers.*.Enabled", false);
if (magnetogramsTextureIndex == 0) then
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Layers.ColorLayers.Texture.Enabled", true);
else
str = "Scene.Sun.Renderable.Layers.ColorLayers.magnetogram-" .. magnetogramsTextureIndex .. ".Enabled";
openspace.setPropertyValueSingle(str, true);
end;
]],
Documentation = "Display next sun texture in list of textures",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function ()
magnetograms = openspace.walkDirectoryFiles(magnetogramDirectory);
rawset(_G, "magnetogramsTextureIndex", -1)
for i, imagename in ipairs(magnetograms) do
openspace.globebrowsing.addLayer(
'Sun',
'ColorLayers',
{
Identifier = "magnetogram-" .. i,
Name = imagename, --"Magnetogram-" .. i,
Description = "",
FilePath = imagename,
Enabled = false
}
)
end
openspace.action.registerAction(switch_color_layer)
end)
asset.onDeinitialize(function ()
for i, imagename in ipairs(magnetograms) do
openspace.globebrowsing.deleteLayer(
'Sun', 'ColorLayers', 'magnetogram-' .. i
)
end
openspace.action.removeAction(switch_color_layer.Identifier)
end)

View File

@@ -0,0 +1,14 @@
width 10
lower 0.0
upper 1.0
mappingkey 0.0 17 17 56 255
mappingkey 0.083 47 38 142 255
mappingkey 0.166 80 39 189 255
mappingkey 0.332 139 49 139 255
mappingkey 0.415 221 60 68 255
mappingkey 0.498 243 95 20 255
mappingkey 0.664 230 147 8 255
mappingkey 0.830 230 195 34 255
mappingkey 0.915 230 226 118 255
mappingkey 1.0 255 255 255 255

View File

@@ -0,0 +1,14 @@
width 10
lower 0.0
upper 1.0
mappingkey 0.0 60 38 164 255
mappingkey 0.083 106 43 167 255
mappingkey 0.166 173 54 110 255
mappingkey 0.332 253 64 40 255
mappingkey 0.415 234 117 6 255
mappingkey 0.498 230 169 16 255
mappingkey 0.664 236 236 159 255
mappingkey 0.830 251 251 235 255
mappingkey 0.915 255 255 255 255
mappingkey 1.0 255 255 255 255

View File

@@ -0,0 +1,14 @@
width 10
lower 0.0
upper 1.0
mappingkey 0.0 0 0 0 0
mappingkey 0.083 30 30 100 255
mappingkey 0.166 60 38 164 255
mappingkey 0.332 106 43 167 255
mappingkey 0.415 173 54 110 255
mappingkey 0.498 253 64 40 255
mappingkey 0.664 234 117 6 255
mappingkey 0.830 230 169 16 255
mappingkey 0.915 236 236 159 255
mappingkey 1.0 251 251 235 255

View File

@@ -0,0 +1,9 @@
width 6
lower 0.0
upper 1.0
mappingkey 0.0 0 0 255 250
mappingkey 0.075 0 0 255 250
mappingkey 0.4 0 255 255 250
mappingkey 0.58 0 255 0 250
mappingkey 0.73 255 255 0 250
mappingkey 1.0 255 0 0 250

View File

@@ -0,0 +1,11 @@
width 7
lower 0.0
upper 1.0
mappingkey 0.0 153 51 255 255
mappingkey 0.166 51 51 255 255
mappingkey 0.332 51 255 255 255
mappingkey 0.498 51 255 51 255
mappingkey 0.664 255 255 51 255
mappingkey 0.830 255 153 51 255
mappingkey 1.0 255 51 51 255

View File

@@ -0,0 +1,7 @@
width 7
lower 0.0
upper 1.0
mappingkey 0.0 45 45 45 255
mappingkey 0.5 45 45 45 255
mappingkey 1.0 45 45 45 255

View File

@@ -0,0 +1,14 @@
width 10
lower 0.0
upper 1.0
mappingkey 0.0 127 0 255 255
mappingkey 0.083 89 59 253 255
mappingkey 0.166 55 90 246 255
mappingkey 0.332 23 152 242 255
mappingkey 0.415 13 194 224 255
mappingkey 0.498 138 254 174 255
mappingkey 0.664 227 197 105 255
mappingkey 0.830 255 128 66 255
mappingkey 0.915 251 79 37 255
mappingkey 1.0 255 0 0 255

View File

@@ -0,0 +1,14 @@
width 2048
lower 0.0
upper 1.0
mappingkey 0.005 0 54 135 0
mappingkey 0.06 0 67 168 10
mappingkey 0.1 100 180 200 70
mappingkey 0.2 180 50 100 100
mappingkey 0.3 180 90 25 150
mappingkey 0.4 200 53 18 255
mappingkey 0.5 255 177 42 255
mappingkey 0.6 255 22 15 255
mappingkey 0.7 255 5 5 255
mappingkey 1.0 255 0 0 255

View File

@@ -0,0 +1,18 @@
width 2048
lower 0.0
upper 1.0
mappingkey 0.000001 50 50 250 2
mappingkey 0.000015 250 250 250 250
mappingkey 0.00025 70 170 255 250
mappingkey 0.004 120 230 255 250
mappingkey 0.0045 255 220 180 250
mappingkey 0.06 255 150 120 250
mappingkey 0.1 255 50 20 250
mappingkey 0.15 250 0 0 200
mappingkey 0.20 250 0 0 200
mappingkey 0.35 250 20 0 200
mappingkey 0.40 250 0 0 200
mappingkey 0.60 250 0 0 200
mappingkey 0.80 250 0 0 255

View File

@@ -0,0 +1,18 @@
width 2048
lower 0.0
upper 1.0
mappingkey 0.005 0 54 135 0
mappingkey 0.06 0 85 125 11
mappingkey 0.1 140 30 70 50
mappingkey 0.13 160 160 0 45
mappingkey 0.16 150 150 150 150
mappingkey 0.2 180 210 255 190
mappingkey 0.3 190 200 255 250
mappingkey 0.4 255 255 255 0
mappingkey 0.5 0 0 0 0
mappingkey 0.6 137 223 255 0
mappingkey 0.7 94 255 214 0
mappingkey 0.8 255 200 180 0
mappingkey 0.9 249 199 150 0
mappingkey 1.0 255 140 100 0

View File

@@ -0,0 +1,18 @@
width 2048
lower 0.0
upper 1.0
mappingkey 0.005 0 54 135 0
mappingkey 0.06 0 145 255 15
mappingkey 0.1 0 130 255 70
mappingkey 0.13 0 200 255 120
mappingkey 0.16 0 255 255 255
mappingkey 0.2 90 210 255 130
mappingkey 0.3 90 200 255 250
mappingkey 0.4 200 200 230 150
mappingkey 0.5 92 177 242 200
mappingkey 0.6 137 223 255 0
mappingkey 0.7 94 255 214 0
mappingkey 0.8 255 200 180 0
mappingkey 0.9 249 199 150 0
mappingkey 1.0 255 140 100 0

View File

@@ -0,0 +1,16 @@
width 2048
lower 0.0
upper 1.0
mappingkey 0.005 0 54 135 0
mappingkey 0.06 0 67 168 3
mappingkey 0.1 90 180 255 75
mappingkey 0.2 0 180 255 55
mappingkey 0.3 0 180 255 70
mappingkey 0.4 7 93 183 50
mappingkey 0.5 0 177 242 10
mappingkey 0.6 1 223 255 9
mappingkey 0.7 94 255 214 0
mappingkey 0.8 255 200 114 0
mappingkey 0.9 249 199 97 0
mappingkey 1.0 255 140 48 0

View File

@@ -0,0 +1,9 @@
width 5
lower 0.0
upper 1.0
mappingkey 0.0 0 0 0 255
mappingkey 0.25 255 0 0 255
mappingkey 0.5 255 140 0 255
mappingkey 0.75 255 255 0 255
mappingkey 1.0 255 255 255 255

View File

@@ -0,0 +1,33 @@
Geocentric Solar Magnetospheric (GSM) frame:
Used by the BATSRUS model
This Kernel's ID is not a valid ID!
+X is parallel to the geometric earth-sun position vector.
+Z axis is normalized component of north centered geomagnetic dipole
vector orthogonal to GSM +X axis.
+Y completes the right-handed frame.
\begindata
FRAME_GSM = 13371333
FRAME_13371333_NAME = 'GSM'
FRAME_13371333_CLASS = 5
FRAME_13371333_CLASS_ID = 13371333
FRAME_13371333_CENTER = 399
FRAME_13371333_RELATIVE = 'GALACTIC'
FRAME_13371333_DEF_STYLE = 'PARAMETERIZED'
FRAME_13371333_FAMILY = 'TWO-VECTOR'
FRAME_13371333_PRI_AXIS = 'X'
FRAME_13371333_PRI_VECTOR_DEF = 'OBSERVER_TARGET_POSITION'
FRAME_13371333_PRI_OBSERVER = 'EARTH'
FRAME_13371333_PRI_TARGET = 'SUN'
FRAME_13371333_PRI_ABCORR = 'NONE'
FRAME_13371333_SEC_AXIS = 'Z'
FRAME_13371333_SEC_VECTOR_DEF = 'CONSTANT'
FRAME_13371333_SEC_FRAME = 'ECLIPJ2000'
FRAME_13371333_SEC_SPEC = 'LATITUDINAL'
FRAME_13371333_SEC_UNITS = 'DEGREES'
FRAME_13371333_SEC_LONGITUDE = 288.43
FRAME_13371333_SEC_LATITUDE = 79.54

View File

@@ -0,0 +1,14 @@
width 10
lower 0.0
upper 1.0
mappingkey 0.0 60 38 164 255
mappingkey 0.083 106 43 167 255
mappingkey 0.166 173 54 110 255
mappingkey 0.332 253 64 40 255
mappingkey 0.415 234 117 6 255
mappingkey 0.498 230 169 16 255
mappingkey 0.664 236 236 159 255
mappingkey 0.830 251 251 235 255
mappingkey 0.915 255 255 255 255
mappingkey 1.0 255 255 255 255

View File

@@ -0,0 +1,50 @@
local assetHelper = asset.require('util/asset_helper')
local transforms = asset.require('./transforms_magnetosphere')
local transferFunction = asset.localResource("./CMR-illuminance2.txt")
local fieldlinesDirectory = asset.syncedResource({
Name = "Magnetosphere 2012 event",
Type = "HttpSynchronization",
Identifier = "magnetosphere_2012_event",
Version = 1
})
local earthMagnetosphere = {
Identifier = "EarthMagnetosphere",
Parent = transforms.GSMReferenceFrame.Identifier,
Renderable = {
Type = "RenderableFieldlinesSequence",
SourceFolder = fieldlinesDirectory,
LineWidth = 1.0,
AlphaBlendlingEnabled = false,
InputFileType = "Osfls", -- OpenSpace Field lines sequence
MaskingEnabled = true,
MaskingQuantity = 5, -- corresponds to "topology"
MaskingRanges = {{-0, 0}},
ColorMethod = "By Quantity",
ColorQuantity = 4,
ColorTableRanges = {{50, 300}},
ColorTablePaths = {transferFunction},
LoadAtRuntime = true,
ScaleToMeters = 1.0,
Color = {
Uniform = { 1.0, 0.725, 0.75, 1.0 }
}
},
GUI = {
Path = "/Solar System/Planets/Earth",
Name = "Magnetosphere"
},
}
assetHelper.registerSceneGraphNodesAndExport(asset, { earthMagnetosphere })
asset.meta = {
Name = "Static generic magnetosphere of fieldlines",
Version = "1.0",
Description = "Magnetic fieldlines for the bastille day CME event",
Author = "CCMC",
URL = "",
License = "",
Identifier = {"EarthMagnetosphere"}
}

View File

@@ -0,0 +1,35 @@
local assetHelper = asset.require('util/asset_helper')
local transforms = asset.require('scene/solarsystem/planets/earth/transforms')
asset.require("spice/base")
local GSMKernel = asset.localResource("../kernels/GSM.ti")
local GSMReferenceFrame = {
Identifier = "GSMReferenceFrame",
Parent = transforms.EarthCenter.Identifier,
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "GSM", --Geocentric Solar Magnetospheric
DestinationFrame = "GALACTIC",
Kernels = GSMKernel
}
},
GUI = {
Name = "GSM Reference Frame",
Path = "/Solar System/Planets/Earth",
Hidden = true
}
}
assetHelper.registerSceneGraphNodesAndExport(asset, { GSMReferenceFrame })
asset.meta = {
Name = "Earth magnetosphere transforms",
Version = "1.0",
Description = "Earth transforms: GSMReferenceFrame. Geocentric Solar Magnetospheric",
Author = "CCMC",
URL = "http://openspaceproject.com",
License = "MIT license",
Identifiers = {"GSMReferenceFrame"}
}

View File

@@ -0,0 +1,57 @@
asset.require("spice/base")
local assetHelper = asset.require("util/asset_helper")
local propertyHelper = asset.require('util/property_helper')
local transforms = asset.require("./transforms")
local textureSourcePath = asset.syncedResource({
Type = "HttpSynchronization",
Name = "euv_textures_bastille_event",
Identifier = "euv_textures_bastille_event",
Version = 1
})
local EUVLayer = {
Identifier = "EUV-Layer-bastille-day-2000",
Parent = transforms.SunIAU.Identifier,
Renderable = {
Type = "RenderableTimeVaryingSphere",
Size = 6.96E8, -- Slightly bigger than the sun renderable,
Enabled = true,
TextureSource = textureSourcePath,
Opacity = 1,
Segments = 132
},
GUI = {
Name = "EUV Layer",
Path = "/Solar System/Sun",
Description = "Texture sequence of an extreme ultra violet (EUV) simulation, during the CME. This asset contains data from 2000-07-14 08:38 to 2000-07-14 19:48"
}
}
local toggle_EUV_layer = {
Identifier = "euv_layer.toggle_EUV",
Name = "Toggle EUV Layer",
Command = propertyHelper.invert("Scene.EUV-Layer-bastille-day-2000.Renderable.Enabled"),
Documentation = "Toggle EUV layer of sun",
GuiPath = "/Bastille-Day 2000",
IsLocal = false
}
asset.onInitialize(function ()
openspace.action.registerAction(toggle_EUV_layer)
end)
asset.onDeinitialize(function ()
openspace.action.removeAction(toggle_EUV_layer.Identifier)
end)
assetHelper.registerSceneGraphNodesAndExport(asset, { EUVLayer })
asset.meta = {
Name = "Predictive Science Inc. EUV texture sequence Bastille Days",
Version = "1.0",
Description = [[Texture sequence of an extreme ultraviolet (EUV) simulation during,
the CME]],
Author = "CCMC, OpenSpace team",
URL = "https://dx.doi.org/10.3847/1538-4357/aab36d",
License = "CC-BY",
Identifier = {"EUV-Layer-bastille-day-2000"}
}

View File

@@ -3,8 +3,8 @@ local colorLayersPath = "./layers/colorlayers"
local colorLayer = asset.require(colorLayersPath .. "/sun_texture")
-- Set enabled layers (temporary solution)
-- @TODO: do this using a boolean that's passed to the 'asset.require' instead
asset.onInitialize(function ()
-- @TODO: do this using a boolean that's passed to the 'asset.require' instead
asset.onInitialize(function ()
openspace.setPropertyValueSingle("Scene.Sun.Renderable.Layers.ColorLayers." .. colorLayer.layer.Identifier .. ".Enabled", true)
end)

View File

@@ -0,0 +1,41 @@
\begintext
Heliocentric Earth Equatorial (HEEQ+180) Frame
Used by the BATSRUS model
This Kernel's ID is not a valid ID!
Definition of the Heliocentric Earth Equatorial frame:
All vectors are geometric: no aberration corrections are
used.
The solar rotation axis is the primary vector: the Z axis points
in the solar north direction.
The position of the sun relative to the earth is the secondary
vector: the X axis is the component of this position vector
orthogonal to the Z axis.
The Y axis is Z cross X, completing the right-handed
reference frame.
\begindata
FRAME_HEEQ180 = 6666666
FRAME_6666666_NAME = 'HEEQ180'
FRAME_6666666_CLASS = 5
FRAME_6666666_CLASS_ID = 6666666
FRAME_6666666_CENTER = 10
FRAME_6666666_RELATIVE = 'J2000'
FRAME_6666666_DEF_STYLE = 'PARAMETERIZED'
FRAME_6666666_FAMILY = 'TWO-VECTOR'
FRAME_6666666_PRI_AXIS = 'Z'
FRAME_6666666_PRI_VECTOR_DEF = 'CONSTANT'
FRAME_6666666_PRI_FRAME = 'IAU_SUN'
FRAME_6666666_PRI_SPEC = 'RECTANGULAR'
FRAME_6666666_PRI_VECTOR = ( 0, 0, 1 )
FRAME_6666666_SEC_AXIS = 'X'
FRAME_6666666_SEC_VECTOR_DEF = 'OBSERVER_TARGET_POSITION'
FRAME_6666666_SEC_OBSERVER = 'EARTH'
FRAME_6666666_SEC_TARGET = 'SUN'
FRAME_6666666_SEC_ABCORR = 'NONE'
FRAME_6666666_SEC_FRAME = 'IAU_SUN'

View File

@@ -92,7 +92,7 @@ asset.meta = {
Name = "Sun Transforms",
Version = "1.0",
Description = [[ Sun transforms: Solar System Barycenter, SUN IAU and
SUN J2000]],
SUN J2000]],
Author = "OpenSpace Team",
URL = "http://openspaceproject.com",
License = "MIT license",

View File

@@ -0,0 +1,39 @@
local assetHelper = asset.require("util/asset_helper")
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
asset.require("spice/base")
local HEEQ180Kernel = asset.localResource("./kernels/HEEQ180.tf")
local HEEQ180ReferenceFrame = {
Identifier = "HEEQ180ReferenceFrame",
-- The HEEQ180 reference frame should have Sun_IAU as parent
-- instead of Solar center, however the Sun_IAU adds
-- an unwanted rotation which is difficult to cancel out
-- since it is using SpiceRotation. Sun center
-- is used instead.
Parent = sunTransforms.SunCenter.Identifier,
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "HEEQ180",
DestinationFrame = "GALACTIC",
Kernels = HEEQ180Kernel
},
},
GUI = {
Name = "HEEQ180 Reference Frame",
Path = "/Solar System/Sun",
Hidden = true
}
}
assetHelper.registerSceneGraphNodesAndExport(asset, { HEEQ180ReferenceFrame })
asset.meta = {
Name = "Sun Transform, HEEQ180",
Version = "1.0",
Description = "Sun transform: HEEQ180",
Author = "CCMC",
URL = "http://openspaceproject.com",
License = "MIT license",
Identifiers = {"HEEQ180ReferenceFrame"}
}

View File

@@ -0,0 +1,8 @@
local TexturesPath = asset.syncedResource({
Type = "HttpSynchronization",
Name = "Streamnodes textures",
Identifier = "streamnodes_textures",
Version = 4
})
asset.export("TexturesPath", TexturesPath)

View File

@@ -0,0 +1,209 @@
{
"actions": [
{
"documentation": "Reset button to start of CME",
"gui_path": "/Bastille-Day 2000",
"identifier": "bastille-day.reset_loops",
"is_local": false,
"name": "Reset button. Start of CME, no loop",
"script": "openspace.time.setTime('2000-JUL-14 10:03:00.00');openspace.scriptScheduler.clear();"
},
{
"documentation": "New loop: Restarts time at 10:03 and stops at 10:16, sets delta time to 2 min/ second (120 seconds/ second)",
"gui_path": "/Bastille-Day 2000",
"identifier": "bastille-day.short_loop",
"is_local": false,
"name": "Loop 10:03 - 10:16, at 2 min/ second",
"script": "openspace.scriptScheduler.clear();openspace.time.setDeltaTime(120);openspace.time.setTime('2000-JUL-14 10:03:00.00');EndtimeShortLoop = \"2000 JUL 14 10:16:00\";StarttimescriptSlowLoop = \"openspace.time.setTime('2000 JUL 14 10:03:00')\";openspace.scriptScheduler.loadScheduledScript(EndtimeShortLoop, StarttimescriptSlowLoop);"
},
{
"documentation": "New loop: Restarts time at 10:03 and stops at 11:00, delta time to 4 min/ second (240 seconds/ second)",
"gui_path": "/Bastille-Day 2000",
"identifier": "bastille-day.standard_loop",
"is_local": false,
"name": "Loop 10:03 - 11:00, at 4 min/ second",
"script": "StarttimescriptSlowLoop = \"openspace.time.setTime('2000 JUL 14 10:03:00')\";openspace.scriptScheduler.clear();openspace.time.setDeltaTime(240);openspace.time.setTime('2000-JUL-14 10:03:00.00');openspace.scriptScheduler.loadScheduledScript('2000 JUL 14 11:00:00', StarttimescriptSlowLoop);"
},
{
"documentation": "Fast loop: Starts from 10:03 and sets delta time to 15 min/ second (900 seconds/ second)",
"gui_path": "/Bastille-Day 2000",
"identifier": "bastille-day.fast_loop",
"is_local": false,
"name": "Loop 10:03 - 11.48, at 15 min/ second",
"script": "openspace.scriptScheduler.clear();openspace.time.setDeltaTime(900);openspace.time.setTime('2000-JUL-14 10:03:00.00');StarttimescriptFastLoop = \"openspace.time.setTime('2000 JUL 14 10:03:00')\";openspace.scriptScheduler.loadScheduledScript('2000 JUL 14 11:48:00', StarttimescriptFastLoop);"
},
{
"documentation": "Long loop: Restarts time at 09:30 and stops at 11:50, delta time to 4 min/ second (240 seconds/ second)",
"gui_path": "/Bastille-Day 2000",
"identifier": "bastille-day.long_loop",
"is_local": false,
"name": "Loop 09:30 - 13:00, at 4 min/ second",
"script": "openspace.scriptScheduler.clear();openspace.time.setDeltaTime(240);openspace.time.setTime('2000-JUL-14 09:30:00.00');StarttimescriptLongLoop = \"openspace.time.setTime('2000 JUL 14 09:30:00')\";openspace.scriptScheduler.loadScheduledScript('2000 JUL 14 13:00:00', StarttimescriptLongLoop);"
}
],
"assets": [
"base",
"dashboard/default_dashboard",
"scene/solarsystem/heliosphere/bastille_day/density_volume",
"scene/solarsystem/heliosphere/bastille_day/fieldlines",
"scene/solarsystem/heliosphere/bastille_day/fluxnodes",
"scene/solarsystem/heliosphere/bastille_day/fluxnodescutplane",
"scene/solarsystem/heliosphere/bastille_day/fluxnodeslegend",
"scene/solarsystem/heliosphere/bastille_day/lightindicator",
"scene/solarsystem/heliosphere/bastille_day/magnetogram",
"scene/solarsystem/heliosphere/bastille_day/magnetogram_textures",
"scene/solarsystem/planets/earth/magnetosphere/magnetosphere",
"scene/solarsystem/planets/earth/magnetosphere/transforms_magnetosphere",
"scene/solarsystem/planets/earth/satellites/satellites",
"scene/solarsystem/sun/euv_layer",
"scene/solarsystem/sun/sun_textures"
],
"camera": {
"altitude": 3400000000.0,
"anchor": "Sun",
"latitude": 20.5877,
"longitude": -35.1924,
"type": "goToGeo"
},
"delta_times": [
1.0,
5.0,
30.0,
60.0,
300.0,
1800.0,
3600.0,
43200.0,
86400.0,
604800.0,
1209600.0,
2592000.0,
5184000.0,
7776000.0,
15552000.0,
31536000.0,
63072000.0,
157680000.0,
315360000.0,
630720000.0
],
"keybindings": [
{
"action": "bastille-day.reset_loops",
"key": "R"
},
{
"action": "bastille-day.short_loop",
"key": "CTRL+1"
},
{
"action": "bastille-day.standard_loop",
"key": "CTRL+2"
},
{
"action": "bastille-day.fast_loop",
"key": "CTRL+3"
},
{
"action": "bastille-day.long_loop",
"key": "CTRL+4"
},
{
"action": "density_volume.toggle_volume",
"key": "D"
},
{
"action": "fluxnodelegend.show_legend",
"key": "N"
},
{
"action": "fluxnodelegend.hide_legend",
"key": "M"
},
{
"action": "magnetogram_texture.switch_color_layer",
"key": "I"
},
{
"action": "euv_layer.toggle_EUV",
"key": "E"
},
{
"action": "fluxnodes.toggle_fluxnodes",
"key": "O"
},
{
"action": "fieldlines.toggle_fieldlines",
"key": "U"
},
{
"action": "fluxnodescutplane.toggle_equatorial",
"key": "P"
},
{
"action": "fluxnodescutplane.toggle_meridial",
"key": "LEFTBRACKET"
}
],
"mark_nodes": [
"Earth",
"Mars",
"Moon",
"Sun",
"Venus",
"ISS"
],
"meta": {
"author": "CCMC",
"description": "This profile is showing the Coronal mass ejection of the bastille day 2000-07-14. The profile is data heavy and will require a powerful GPU.",
"license": "MIT License",
"name": "Bastille day",
"url": "https://www.openspaceproject.com",
"version": "1.0"
},
"properties": [
{
"name": "{earth_satellites}.Renderable.Enabled",
"type": "setPropertyValue",
"value": "false"
},
{
"name": "Scene.Sun.Renderable.Enabled",
"type": "setPropertyValue",
"value": "true"
},
{
"name": "Scene.SunGlare.Renderable.Enabled",
"type": "setPropertyValue",
"value": "false"
},
{
"name": "Scene.Sun.Renderable.Layers.ColorLayers.Texture.Enabled",
"type": "setPropertyValue",
"value": "false"
},
{
"name": "Scene.Sun.Renderable.Layers.ColorLayers.magnetogram-2.Enabled",
"type": "setPropertyValue",
"value": "true"
},
{
"name": "Scene.Earth.Renderable.Layers.ColorLayers.ESRI_VIIRS_Combo.Enabled",
"type": "setPropertyValue",
"value": "false"
},
{
"name": "Scene.Earth.Renderable.Layers.ColorLayers.ESRI_World_Imagery.Enabled",
"type": "setPropertyValue",
"value": "true"
}
],
"time": {
"type": "absolute",
"value": "2000-07-14T08:42:00"
},
"version": {
"major": 1,
"minor": 1
}
}

View File

@@ -33,6 +33,7 @@ namespace openspace::distanceconstants {
constexpr double LightMonth = LightYear / 12;
constexpr double LightDay = LightYear / 365;
constexpr double LightHour = LightDay / 24;
constexpr double LightSecond = 299792458.0;
constexpr double AstronomicalUnit = 1.495978707E11;
constexpr double Parsec = 3.0856776E16;

View File

@@ -50,8 +50,10 @@ set(HEADER_FILES
rendering/renderableplane.h
rendering/renderableplaneimagelocal.h
rendering/renderableplaneimageonline.h
rendering/renderableplanetimevaryingimage.h
rendering/renderableprism.h
rendering/renderablesphere.h
rendering/renderabletimevaryingsphere.h
rendering/renderabletrail.h
rendering/renderabletrailorbit.h
rendering/renderabletrailtrajectory.h
@@ -102,8 +104,10 @@ set(SOURCE_FILES
rendering/renderableplane.cpp
rendering/renderableplaneimagelocal.cpp
rendering/renderableplaneimageonline.cpp
rendering/renderableplanetimevaryingimage.cpp
rendering/renderableprism.cpp
rendering/renderablesphere.cpp
rendering/renderabletimevaryingsphere.cpp
rendering/renderabletrail.cpp
rendering/renderabletrailorbit.cpp
rendering/renderabletrailtrajectory.cpp

View File

@@ -51,7 +51,9 @@
#include <modules/base/rendering/renderabletrailtrajectory.h>
#include <modules/base/rendering/renderableplaneimagelocal.h>
#include <modules/base/rendering/renderableplaneimageonline.h>
#include <modules/base/rendering/renderableplanetimevaryingimage.h>
#include <modules/base/rendering/renderableprism.h>
#include <modules/base/rendering/renderabletimevaryingsphere.h>
#include <modules/base/rendering/screenspacedashboard.h>
#include <modules/base/rendering/screenspaceimagelocal.h>
#include <modules/base/rendering/screenspaceimageonline.h>
@@ -132,7 +134,9 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) {
fRenderable->registerClass<RenderableNodeLine>("RenderableNodeLine");
fRenderable->registerClass<RenderablePlaneImageLocal>("RenderablePlaneImageLocal");
fRenderable->registerClass<RenderablePlaneImageOnline>("RenderablePlaneImageOnline");
fRenderable->registerClass<RenderablePlaneTimeVaryingImage>("RenderablePlaneTimeVaryingImage");
fRenderable->registerClass<RenderablePrism>("RenderablePrism");
fRenderable->registerClass<RenderableTimeVaryingSphere>("RenderableTimeVaryingSphere");
fRenderable->registerClass<RenderableRadialGrid>("RenderableRadialGrid");
fRenderable->registerClass<RenderableSphere>("RenderableSphere");
fRenderable->registerClass<RenderableSphericalGrid>("RenderableSphericalGrid");
@@ -201,10 +205,12 @@ std::vector<documentation::Documentation> BaseModule::documentations() const {
RenderablePlane::Documentation(),
RenderablePlaneImageLocal::Documentation(),
RenderablePlaneImageOnline::Documentation(),
RenderablePlaneTimeVaryingImage::Documentation(),
RenderableRadialGrid::Documentation(),
RenderableDisc::Documentation(),
RenderableSphere::Documentation(),
RenderableSphericalGrid::Documentation(),
RenderableTimeVaryingSphere::Documentation(),
RenderableTrailOrbit::Documentation(),
RenderableTrailTrajectory::Documentation(),

View File

@@ -89,6 +89,7 @@ void DashboardItemDate::render(glm::vec2& penPosition) {
global::timeManager->time().j2000Seconds(),
_timeFormat.value().c_str()
);
try {
RenderFont(*_font, penPosition, fmt::format(_formatString.value().c_str(), time));
}

View File

@@ -58,6 +58,14 @@ namespace {
"transformations."
};
constexpr openspace::properties::Property::PropertyInfo MirrorBacksideInfo = {
"MirrorBackside",
"Mirror backside of image plane",
"If this value is set to false, the image plane will not be mirrored when "
"looking from the backside. This is usually desirable when the image shows "
"data at a specific location, but not if it is displaying text for example."
};
constexpr openspace::properties::Property::PropertyInfo SizeInfo = {
"Size",
"Size (in meters)",
@@ -81,6 +89,9 @@ namespace {
// [[codegen::verbatim(BillboardInfo.description)]]
std::optional<bool> billboard;
// [[codegen::verbatim(MirrorBacksideInfo.description)]]
std::optional<bool> mirrorBackside;
// [[codegen::verbatim(SizeInfo.description)]]
float size;
@@ -107,6 +118,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _blendMode(BlendModeInfo, properties::OptionProperty::DisplayType::Dropdown)
, _billboard(BillboardInfo, false)
, _mirrorBackside(MirrorBacksideInfo, false)
, _size(SizeInfo, 10.f, 0.f, 1e25f)
, _multiplyColor(MultiplyColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
{
@@ -117,6 +129,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary)
_size = p.size;
_billboard = p.billboard.value_or(_billboard);
_mirrorBackside = p.mirrorBackside.value_or(_mirrorBackside);
_blendMode.addOptions({
{ static_cast<int>(BlendMode::Normal), "Normal" },
@@ -211,6 +224,8 @@ void RenderablePlane::render(const RenderData& data, RendererTasks&) {
_shader->activate();
_shader->setUniform("opacity", _opacity);
_shader->setUniform("mirrorBackside", _mirrorBackside);
glm::dvec3 objectPositionWorld = glm::dvec3(
glm::translate(
glm::dmat4(1.0),

View File

@@ -75,6 +75,7 @@ private:
void createPlane();
properties::BoolProperty _billboard;
properties::BoolProperty _mirrorBackside;
properties::FloatProperty _size;
properties::Vec3Property _multiplyColor;

View File

@@ -0,0 +1,321 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include <modules/base/rendering/renderableplanetimevaryingimage.h>
#include <modules/base/basemodule.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/logging/logmanager.h>
#include <optional>
namespace {
constexpr const char* KeyLazyLoading = "LazyLoading";
constexpr const char* _loggerCat = "RenderablePlaneTimeVaryingImage";
constexpr openspace::properties::Property::PropertyInfo SourceFolderInfo = {
"SourceFolder",
"Source Folder",
"This value specifies the image directory that is loaded from disk and "
"is used as a texture that is applied to this plane."
};
constexpr openspace::properties::Property::PropertyInfo RenderTypeInfo = {
"RenderType",
"Render Type",
"This value specifies if the plane should be rendered in the Background, "
"Opaque, Transparent, or Overlay rendering step."
};
struct [[codegen::Dictionary(RenderablePlaneTimeVaryingImage)]] Parameters {
// [[codegen::verbatim(SourceFolderInfo.description)]]
std::string sourceFolder;
enum class RenderType {
Background,
Opaque,
PreDeferredTransparency,
PostDeferredTransparency,
Overlay
};
// [[codegen::verbatim(RenderTypeInfo.description)]]
std::optional<RenderType> renderType;
};
#include "renderableplanetimevaryingimage_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation RenderablePlaneTimeVaryingImage::Documentation() {
documentation::Documentation doc = codegen::doc<Parameters>(
"base_renderable_plane_time_varying_image"
);
// Insert the parents documentation entries until we have a verifier that can deal
// with class hierarchy
documentation::Documentation parentDoc = RenderablePlane::Documentation();
doc.entries.insert(
doc.entries.end(),
parentDoc.entries.begin(),
parentDoc.entries.end()
);
return doc;
}
RenderablePlaneTimeVaryingImage::RenderablePlaneTimeVaryingImage(
const ghoul::Dictionary& dictionary)
: RenderablePlane(dictionary)
, _sourceFolder(SourceFolderInfo)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
addProperty(_blendMode);
_sourceFolder = p.sourceFolder;
if (!std::filesystem::is_directory(absPath(_sourceFolder))) {
LERROR(fmt::format(
"Time varying image, {} is not a valid directory",
_sourceFolder
));
}
addProperty(_sourceFolder);
_sourceFolder.onChange([this]() { _texture = loadTexture(); });
if (p.renderType.has_value()) {
switch (*p.renderType) {
case Parameters::RenderType::Background:
setRenderBin(Renderable::RenderBin::Background);
break;
case Parameters::RenderType::Opaque:
setRenderBin(Renderable::RenderBin::Opaque);
break;
case Parameters::RenderType::PreDeferredTransparency:
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
break;
case Parameters::RenderType::PostDeferredTransparency:
setRenderBin(Renderable::RenderBin::PostDeferredTransparent);
break;
case Parameters::RenderType::Overlay:
setRenderBin(Renderable::RenderBin::Overlay);
break;
}
}
else {
setRenderBin(Renderable::RenderBin::Opaque);
}
if (dictionary.hasKey(KeyLazyLoading)) {
_isLoadingLazily = dictionary.value<bool>(KeyLazyLoading);
if (_isLoadingLazily) {
_enabled.onChange([this]() {
if (_enabled) {
_textureIsDirty = true;
}
else {
BaseModule::TextureManager.release(_texture);
_texture = nullptr;
}
});
}
}
}
void RenderablePlaneTimeVaryingImage::initialize() {
RenderablePlane::initialize();
bool success = extractMandatoryInfoFromDictionary();
if (!success) {
return;
}
extractTriggerTimesFromFileNames();
computeSequenceEndTime();
}
void RenderablePlaneTimeVaryingImage::initializeGL() {
RenderablePlane::initializeGL();
_textureFiles.resize(_sourceFiles.size());
for (size_t i = 0; i < _sourceFiles.size(); ++i) {
_textureFiles[i] = ghoul::io::TextureReader::ref().loadTexture(
absPath(_sourceFiles[i]).string()
);
_textureFiles[i]->setInternalFormat(GL_COMPRESSED_RGBA);
_textureFiles[i]->uploadTexture();
_textureFiles[i]->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
_textureFiles[i]->purgeFromRAM();
}
if (!_isLoadingLazily) {
_texture = loadTexture();
}
}
bool RenderablePlaneTimeVaryingImage::extractMandatoryInfoFromDictionary() {
// Ensure that the source folder exists and then extract
// the files with the same extension as <inputFileTypeString>
namespace fs = std::filesystem;
fs::path sourceFolder = absPath(_sourceFolder);
// Extract all file paths from the provided folder
_sourceFiles.clear();
namespace fs = std::filesystem;
for (const fs::directory_entry& e : fs::directory_iterator(sourceFolder)) {
if (e.is_regular_file()) {
_sourceFiles.push_back(e.path().string());
}
}
std::sort(_sourceFiles.begin(), _sourceFiles.end());
// Ensure that there are available and valid source files left
if (_sourceFiles.empty()) {
LERROR(fmt::format(
"{}: Plane sequence filepath {} was empty",
_identifier, _sourceFolder
));
return false;
}
return true;
}
void RenderablePlaneTimeVaryingImage::deinitializeGL() {
BaseModule::TextureManager.release(_texture);
_textureFiles.clear();
RenderablePlane::deinitializeGL();
}
void RenderablePlaneTimeVaryingImage::bindTexture() {
if (_texture && !_textureIsDirty) {
_texture->bind();
}
}
void RenderablePlaneTimeVaryingImage::update(const UpdateData& data) {
ZoneScoped
RenderablePlane::update(data);
if (!_enabled || _startTimes.empty()) {
return;
}
bool needsUpdate = false;
const double currentTime = data.time.j2000Seconds();
bool isInInterval = (currentTime >= _startTimes[0]) &&
(currentTime < _sequenceEndTime);
if (isInInterval) {
const size_t nextIdx = _activeTriggerTimeIndex + 1;
if (
// true => We stepped back to a time represented by another state
currentTime < _startTimes[_activeTriggerTimeIndex] ||
// true => We stepped forward to a time represented by another state
(nextIdx < _sourceFiles.size() && currentTime >= _startTimes[nextIdx]))
{
_activeTriggerTimeIndex = updateActiveTriggerTimeIndex(currentTime);
needsUpdate = true;
} // else we're still in same state as previous frame (no changes needed)
}
else {
// not in interval => set everything to false
_activeTriggerTimeIndex = -1;
needsUpdate = false;
}
if (needsUpdate || _textureIsDirty) {
_texture = loadTexture();
_textureIsDirty = false;
}
}
void RenderablePlaneTimeVaryingImage::render(const RenderData& data, RendererTasks& t) {
if (!_startTimes.empty() &&
data.time.j2000Seconds() < _sequenceEndTime &&
data.time.j2000Seconds() > _startTimes[0])
{
glDisable(GL_CULL_FACE);
RenderablePlane::render(data, t);
}
}
// Requires time to be formated as such: 'YYYY-MM-DDTHH-MM-SS-XXX'
void RenderablePlaneTimeVaryingImage::extractTriggerTimesFromFileNames() {
for (const std::string& filePath : _sourceFiles) {
// Extract the filename from the path (without extension)
std::string timeString = std::filesystem::path(filePath).stem().string();
// Ensure the separators are correct
timeString.replace(4, 1, "-");
timeString.replace(7, 1, "-");
timeString.replace(13, 1, ":");
timeString.replace(16, 1, ":");
timeString.replace(19, 1, ".");
const double triggerTime = Time::convertTime(timeString);
_startTimes.push_back(triggerTime);
}
}
int RenderablePlaneTimeVaryingImage::updateActiveTriggerTimeIndex(
double currentTime) const
{
int activeIndex = 0;
auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), currentTime);
if (iter != _startTimes.end()) {
if (iter != _startTimes.begin()) {
std::ptrdiff_t idx = std::distance(_startTimes.begin(), iter);
activeIndex = static_cast<int>(idx) - 1;
}
else {
activeIndex = 0;
}
}
else {
activeIndex = static_cast<int>(_sourceFiles.size() - 1);
}
return activeIndex;
}
void RenderablePlaneTimeVaryingImage::computeSequenceEndTime() {
if (_sourceFiles.size() > 1) {
const double lastTriggerTime = _startTimes[_sourceFiles.size() - 1];
const double sequenceDuration = lastTriggerTime - _startTimes[0];
const double averageStateDuration = sequenceDuration /
(static_cast<double>(_sourceFiles.size() - 1.0));
_sequenceEndTime = lastTriggerTime + averageStateDuration;
}
}
ghoul::opengl::Texture* RenderablePlaneTimeVaryingImage::loadTexture() const {
ghoul::opengl::Texture* texture = nullptr;
if (_activeTriggerTimeIndex != -1) {
texture = _textureFiles[_activeTriggerTimeIndex].get();
}
return texture;
}
} // namespace openspace

View File

@@ -0,0 +1,77 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEPLANETIMEVARYINGIMAGE___H__
#define __OPENSPACE_MODULE_BASE___RENDERABLEPLANETIMEVARYINGIMAGE___H__
#include <modules/base/rendering/renderableplane.h>
namespace ghoul::filesystem { class File; }
namespace ghoul::opengl { class Texture; }
namespace openspace {
struct RenderData;
struct UpdateData;
namespace documentation { struct Documentation; }
class RenderablePlaneTimeVaryingImage : public RenderablePlane {
public:
RenderablePlaneTimeVaryingImage(const ghoul::Dictionary& dictionary);
void initialize() override;
void initializeGL() override;
void deinitializeGL() override;
void update(const UpdateData& data) override;
void render(const RenderData& data, RendererTasks&) override;
static documentation::Documentation Documentation();
protected:
virtual void bindTexture() override;
private:
ghoul::opengl::Texture* loadTexture() const;
void extractTriggerTimesFromFileNames();
bool extractMandatoryInfoFromDictionary();
int updateActiveTriggerTimeIndex(double currenttime) const;
void computeSequenceEndTime();
// If there's just one state it should never disappear
double _sequenceEndTime = std::numeric_limits<double>::max();
std::vector<std::string> _sourceFiles;
std::vector<double> _startTimes;
int _activeTriggerTimeIndex = 0;
properties::StringProperty _sourceFolder;
ghoul::opengl::Texture* _texture = nullptr;
std::vector<std::unique_ptr<ghoul::opengl::Texture>> _textureFiles;
bool _isLoadingLazily = false;
bool _textureIsDirty = false;
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_BASE___RENDERABLEPLANETIMEVARYINGIMAGE___H__

View File

@@ -0,0 +1,553 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include <modules/base/rendering/renderabletimevaryingsphere.h>
#include <modules/base/basemodule.h>
#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/engine/globals.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/sphere.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/glm.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/crc32.h>
#include <ghoul/opengl/texture.h>
#include <ghoul/opengl/textureunit.h>
#include <ghoul/opengl/programobject.h>
#include <filesystem>
#include <optional>
namespace {
constexpr const char* ProgramName = "Timevarying Sphere";
constexpr const char* _loggerCat = "RenderableTimeVaryingSphere";
constexpr const std::array<const char*, 5> UniformNames = {
"opacity", "modelViewProjection", "modelViewRotation", "colorTexture",
"mirrorTexture"
};
enum class Orientation {
Outside = 0,
Inside,
Both
};
constexpr openspace::properties::Property::PropertyInfo TextureSourceInfo = {
"TextureSource",
"Texture Source",
"This value specifies a directory of images that are loaded from disk and is "
"used as a texture that is applied to this sphere. The images are expected to "
"be an equirectangular projection."
};
constexpr openspace::properties::Property::PropertyInfo MirrorTextureInfo = {
"MirrorTexture",
"Mirror Texture",
"Mirror the texture along the x-axis."
};
constexpr openspace::properties::Property::PropertyInfo OrientationInfo = {
"Orientation",
"Orientation",
"Specifies whether the texture is applied to the inside of the sphere, the "
"outside of the sphere, or both."
};
constexpr openspace::properties::Property::PropertyInfo UseAdditiveBlendingInfo = {
"UseAdditiveBlending",
"Use Additive Blending",
"Render the object using additive blending."
};
constexpr openspace::properties::Property::PropertyInfo SegmentsInfo = {
"Segments",
"Number of Segments",
"This value specifies the number of segments that the sphere is separated in."
};
constexpr openspace::properties::Property::PropertyInfo SizeInfo = {
"Size",
"Size (in meters)",
"This value specifies the radius of the sphere in meters."
};
constexpr openspace::properties::Property::PropertyInfo FadeOutThresholdInfo = {
"FadeOutThreshold",
"Fade-Out Threshold",
"This value determines percentage of the sphere is visible before starting "
"fading-out it."
};
constexpr openspace::properties::Property::PropertyInfo FadeInThresholdInfo = {
"FadeInThreshold",
"Fade-In Threshold",
"Distance from center of MilkyWay from where the astronomical object starts to "
"fade in."
};
constexpr openspace::properties::Property::PropertyInfo DisableFadeInOutInfo = {
"DisableFadeInOut",
"Disable Fade-In/Fade-Out effects",
"Enables/Disables the Fade-In/Out effects."
};
constexpr openspace::properties::Property::PropertyInfo BackgroundInfo = {
"Background",
"Render as Background",
"If this value is set, the sphere is rendered in the background rendering bin, "
"causing it to be rendered before most other scene graph nodes"
};
struct [[codegen::Dictionary(RenerableTimeVaryingSphere)]] Parameters {
// [[codegen::verbatim(SizeInfo.description)]]
float size;
// [[codegen::verbatim(SegmentsInfo.description)]]
int segments;
// [[codegen::verbatim(TextureSourceInfo.description)]]
std::string textureSource;
enum class Orientation {
Outside,
Inside,
Both
};
// [[codegen::verbatim(OrientationInfo.description)]]
std::optional<Orientation> orientation;
// [[codegen::verbatim(UseAdditiveBlendingInfo.description)]]
std::optional<bool> useAdditiveBlending;
// [[codegen::verbatim(MirrorTextureInfo.description)]]
std::optional<bool> mirrorTexture;
// [[codegen::verbatim(FadeOutThresholdInfo.description)]]
std::optional<float> fadeOutThreshold [[codegen::inrange(0.0, 1.0)]];
// [[codegen::verbatim(FadeInThresholdInfo.description)]]
std::optional<float> fadeInThreshold;
// [[codegen::verbatim(DisableFadeInOutInfo.description)]]
std::optional<bool> disableFadeInOut;
// [[codegen::verbatim(BackgroundInfo.description)]]
std::optional<bool> background;
};
#include "renderabletimevaryingsphere_codegen.cpp"
} // namespace
namespace openspace {
double extractTriggerTimeFromFileName(const std::string& filePath);
documentation::Documentation RenderableTimeVaryingSphere::Documentation() {
return codegen::doc<Parameters>("base_renderable_time_varying_sphere");
}
RenderableTimeVaryingSphere::RenderableTimeVaryingSphere(
const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _textureSourcePath(TextureSourceInfo)
, _orientation(OrientationInfo, properties::OptionProperty::DisplayType::Dropdown)
, _size(SizeInfo, 1.f, 0.f, 1e35f)
, _segments(SegmentsInfo, 8, 4, 1000)
, _mirrorTexture(MirrorTextureInfo, false)
, _useAdditiveBlending(UseAdditiveBlendingInfo, false)
, _disableFadeInDistance(DisableFadeInOutInfo, true)
, _backgroundRendering(BackgroundInfo, false)
, _fadeInThreshold(FadeInThresholdInfo, -1.f, -1.f, 1.f)
, _fadeOutThreshold(FadeOutThresholdInfo, -1.f, -1.f, 1.f)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
addProperty(_opacity);
registerUpdateRenderBinFromOpacity();
_size = p.size;
_segments = p.segments;
_textureSourcePath = p.textureSource;
_orientation.addOptions({
{ static_cast<int>(Orientation::Outside), "Outside" },
{ static_cast<int>(Orientation::Inside), "Inside" },
{ static_cast<int>(Orientation::Both), "Both" }
});
if (p.orientation.has_value()) {
switch (*p.orientation) {
case Parameters::Orientation::Inside:
_orientation = static_cast<int>(Orientation::Inside);
break;
case Parameters::Orientation::Outside:
_orientation = static_cast<int>(Orientation::Outside);
break;
case Parameters::Orientation::Both:
_orientation = static_cast<int>(Orientation::Both);
break;
default:
throw ghoul::MissingCaseException();
}
}
else {
_orientation = static_cast<int>(Orientation::Outside);
}
addProperty(_orientation);
_size.setExponent(20.f);
_size.onChange([this]() {
setBoundingSphere(_size);
_sphereIsDirty = true;
});
addProperty(_size);
addProperty(_segments);
_segments.onChange([this]() { _sphereIsDirty = true; });
addProperty(_mirrorTexture);
addProperty(_useAdditiveBlending);
addProperty(_fadeOutThreshold);
addProperty(_fadeInThreshold);
_mirrorTexture = p.mirrorTexture.value_or(_mirrorTexture);
_useAdditiveBlending = p.useAdditiveBlending.value_or(_useAdditiveBlending);
_fadeOutThreshold = p.fadeOutThreshold.value_or(_fadeOutThreshold);
_fadeInThreshold = p.fadeInThreshold.value_or(_fadeInThreshold);
if (_useAdditiveBlending) {
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
}
if (_fadeOutThreshold || _fadeInThreshold) {
_disableFadeInDistance = false;
addProperty(_disableFadeInDistance);
}
_backgroundRendering = p.background.value_or(_backgroundRendering);
if (_backgroundRendering) {
setRenderBin(Renderable::RenderBin::Background);
}
setBoundingSphere(_size);
setRenderBinFromOpacity();
}
bool RenderableTimeVaryingSphere::isReady() const {
return _shader && _texture;
}
void RenderableTimeVaryingSphere::initializeGL() {
_sphere = std::make_unique<Sphere>(_size, _segments);
_sphere->initialize();
_shader = BaseModule::ProgramObjectManager.request(
ProgramName,
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
return global::renderEngine->buildRenderProgram(
ProgramName,
absPath("${MODULE_BASE}/shaders/sphere_vs.glsl"),
absPath("${MODULE_BASE}/shaders/sphere_fs.glsl")
);
}
);
_shader->setIgnoreUniformLocationError(
ghoul::opengl::ProgramObject::IgnoreError::Yes
);
ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
extractMandatoryInfoFromSourceFolder();
computeSequenceEndTime();
loadTexture();
}
void RenderableTimeVaryingSphere::deinitializeGL() {
_texture = nullptr;
BaseModule::ProgramObjectManager.release(
ProgramName,
[](ghoul::opengl::ProgramObject* p) {
global::renderEngine->removeRenderProgram(p);
}
);
_files.clear();
_shader = nullptr;
}
void RenderableTimeVaryingSphere::render(const RenderData& data, RendererTasks&) {
Orientation orientation = static_cast<Orientation>(_orientation.value());
glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
glm::dmat4(data.modelTransform.rotation) *
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale));
glm::dmat3 modelRotation = data.modelTransform.rotation;
_shader->activate();
glm::mat4 modelViewProjection = data.camera.projectionMatrix() *
glm::mat4(data.camera.combinedViewMatrix() * modelTransform);
_shader->setUniform(_uniformCache.modelViewProjection, modelViewProjection);
glm::mat3 modelViewRotation = glm::mat3(
glm::dmat3(data.camera.viewRotationMatrix()) * modelRotation
);
_shader->setUniform(_uniformCache.modelViewRotation, modelViewRotation);
float adjustedOpacity = _opacity;
if (!_disableFadeInDistance) {
if (_fadeInThreshold > -1.0) {
const float logDistCamera = glm::log(static_cast<float>(
glm::distance(data.camera.positionVec3(), data.modelTransform.translation)
));
const float startLogFadeDistance = glm::log(_size * _fadeInThreshold);
const float stopLogFadeDistance = startLogFadeDistance + 1.f;
if (logDistCamera > startLogFadeDistance &&
logDistCamera < stopLogFadeDistance)
{
const float fadeFactor = glm::clamp(
(logDistCamera - startLogFadeDistance) /
(stopLogFadeDistance - startLogFadeDistance),
0.f,
1.f
);
adjustedOpacity *= fadeFactor;
}
else if (logDistCamera <= startLogFadeDistance) {
adjustedOpacity = 0.f;
}
}
if (_fadeOutThreshold > -1.0) {
const float logDistCamera = glm::log(static_cast<float>(
glm::distance(data.camera.positionVec3(), data.modelTransform.translation)
));
const float startLogFadeDistance = glm::log(_size * _fadeOutThreshold);
const float stopLogFadeDistance = startLogFadeDistance + 1.f;
if (logDistCamera > startLogFadeDistance &&
logDistCamera < stopLogFadeDistance)
{
const float fadeFactor = glm::clamp(
(logDistCamera - startLogFadeDistance) /
(stopLogFadeDistance - startLogFadeDistance),
0.f,
1.f
);
adjustedOpacity *= (1.f - fadeFactor);
}
else if (logDistCamera >= stopLogFadeDistance) {
adjustedOpacity = 0.f;
}
}
}
// Performance wise
if (adjustedOpacity < 0.01f) {
return;
}
_shader->setUniform(_uniformCache.opacity, adjustedOpacity);
_shader->setUniform(_uniformCache._mirrorTexture, _mirrorTexture);
ghoul::opengl::TextureUnit unit;
unit.activate();
_texture->bind();
_shader->setUniform(_uniformCache.colorTexture, unit);
// Setting these states should not be necessary,
// since they are the default state in OpenSpace.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
if (orientation == Orientation::Inside) {
glCullFace(GL_FRONT);
}
else if (orientation == Orientation::Both) {
glDisable(GL_CULL_FACE);
}
if (_useAdditiveBlending) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDepthMask(false);
}
_sphere->render();
if (_useAdditiveBlending) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(true);
}
_shader->setIgnoreUniformLocationError(ghoul::opengl::ProgramObject::IgnoreError::No);
_shader->deactivate();
if (orientation == Orientation::Inside) {
glCullFace(GL_BACK);
}
else if (orientation == Orientation::Both) {
glEnable(GL_CULL_FACE);
}
glDisable(GL_CULL_FACE);
}
void RenderableTimeVaryingSphere::extractMandatoryInfoFromSourceFolder() {
// Ensure that the source folder exists and then extract
// the files with the same extension as <inputFileTypeString>
namespace fs = std::filesystem;
fs::path sourceFolder = absPath(_textureSourcePath);
if (!std::filesystem::is_directory(sourceFolder)) {
throw ghoul::RuntimeError(
"Source folder for timevaryingsphere is not a valid directory"
);
}
// Extract all file paths from the provided folder
_files.clear();
namespace fs = std::filesystem;
for (const fs::directory_entry& e : fs::directory_iterator(sourceFolder)) {
if (!e.is_regular_file()) {
continue;
}
std::string filePath = e.path().string();
double time = extractTriggerTimeFromFileName(filePath);
std::unique_ptr<ghoul::opengl::Texture> t =
ghoul::io::TextureReader::ref().loadTexture(filePath);
t->setInternalFormat(GL_COMPRESSED_RGBA);
t->uploadTexture();
t->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
t->purgeFromRAM();
_files.push_back({ filePath, time, std::move(t) });
}
std::sort(
_files.begin(), _files.end(),
[](const FileData& a, const FileData& b) {
return a.time < b.time;
}
);
// Ensure that there are available and valid source files left
if (_files.empty()) {
throw ghoul::RuntimeError(
"Source folder for timevaryingsphere contains no files"
);
}
}
void RenderableTimeVaryingSphere::update(const UpdateData& data) {
if (!_enabled) {
return;
}
if (_shader->isDirty()) {
_shader->rebuildFromFile();
ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
}
const double currentTime = data.time.j2000Seconds();
const bool isInInterval = (currentTime >= _files[0].time) &&
(currentTime < _sequenceEndTime);
if (isInInterval) {
const size_t nextIdx = _activeTriggerTimeIndex + 1;
if (
// true => We stepped back to a time represented by another state
currentTime < _files[_activeTriggerTimeIndex].time ||
// true => We stepped forward to a time represented by another state
(nextIdx < _files.size() && currentTime >= _files[nextIdx].time))
{
updateActiveTriggerTimeIndex(currentTime);
_sphereIsDirty = true;
} // else {we're still in same state as previous frame (no changes needed)}
}
else {
// not in interval => set everything to false
_activeTriggerTimeIndex = 0;
}
if (_sphereIsDirty) {
_sphere = std::make_unique<Sphere>(_size, _segments);
_sphere->initialize();
loadTexture();
_sphereIsDirty = false;
}
}
// Extract J2000 time from file names
// Requires files to be named as such: 'YYYY-MM-DDTHH-MM-SS-XXX.png'
double extractTriggerTimeFromFileName(const std::string& filePath) {
// Extract the filename from the path (without extension)
std::string timeString = std::filesystem::path(filePath).stem().string();
// Ensure the separators are correct
timeString.replace(4, 1, "-");
timeString.replace(7, 1, "-");
timeString.replace(13, 1, ":");
timeString.replace(16, 1, ":");
timeString.replace(19, 1, ".");
return Time::convertTime(timeString);
}
void RenderableTimeVaryingSphere::updateActiveTriggerTimeIndex(double currentTime) {
auto iter = std::upper_bound(
_files.begin(), _files.end(), currentTime,
[](double value, const FileData& f) {
return value < f.time;
}
);
if (iter != _files.end()) {
if (iter != _files.begin()) {
ptrdiff_t idx = std::distance(_files.begin(), iter);
_activeTriggerTimeIndex = static_cast<int>(idx - 1);
}
else {
_activeTriggerTimeIndex = 0;
}
}
else {
_activeTriggerTimeIndex = static_cast<int>(_files.size()) - 1;
}
}
void RenderableTimeVaryingSphere::computeSequenceEndTime() {
if (_files.size() > 1) {
const double lastTriggerTime = _files[_files.size() - 1].time;
const double sequenceDuration = lastTriggerTime - _files[0].time;
const double averageStateDuration = sequenceDuration /
(static_cast<double>(_files.size()) - 1.0);
_sequenceEndTime = lastTriggerTime + averageStateDuration;
}
}
void RenderableTimeVaryingSphere::loadTexture() {
if (_activeTriggerTimeIndex != -1) {
_texture = _files[_activeTriggerTimeIndex].texture.get();
}
}
} // namespace openspace

View File

@@ -0,0 +1,105 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_BASE___RENDERABLETIMEVARYINGSPHERE___H__
#define __OPENSPACE_MODULE_BASE___RENDERABLETIMEVARYINGSPHERE___H__
#include <openspace/rendering/renderable.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <ghoul/opengl/uniformcache.h>
namespace ghoul::opengl {
class ProgramObject;
class Texture;
} // namespace ghoul::opengl
namespace openspace {
class Sphere;
struct RenderData;
struct UpdateData;
namespace documentation { struct Documentation; }
class RenderableTimeVaryingSphere : public Renderable {
public:
RenderableTimeVaryingSphere(const ghoul::Dictionary& dictionary);
void initializeGL() override;
void deinitializeGL() override;
bool isReady() const override;
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
static documentation::Documentation Documentation();
private:
struct FileData {
std::string path;
double time;
std::unique_ptr<ghoul::opengl::Texture> texture;
};
void loadTexture();
void extractMandatoryInfoFromSourceFolder();
void updateActiveTriggerTimeIndex(double currenttime);
void computeSequenceEndTime();
// If there's just one state it should never disappear!
double _sequenceEndTime = std::numeric_limits<double>::max();
std::vector<FileData> _files;
int _activeTriggerTimeIndex = 0;
properties::StringProperty _textureSourcePath;
properties::OptionProperty _orientation;
properties::FloatProperty _size;
properties::IntProperty _segments;
properties::BoolProperty _mirrorTexture;
properties::BoolProperty _useAdditiveBlending;
properties::BoolProperty _disableFadeInDistance;
properties::BoolProperty _backgroundRendering;
properties::FloatProperty _fadeInThreshold;
properties::FloatProperty _fadeOutThreshold;
ghoul::opengl::ProgramObject* _shader = nullptr;
ghoul::opengl::Texture* _texture = nullptr;
std::unique_ptr<Sphere> _sphere;
UniformCache(opacity, modelViewProjection, modelViewRotation, colorTexture,
_mirrorTexture) _uniformCache;
bool _sphereIsDirty = false;
};
} // namespace openspace
#endif // __OPENSPACE_MODULE_BASE___RENDERABLETIMEVARYINGSPHERE___H__

View File

@@ -32,6 +32,7 @@ in vec2 vs_st;
uniform sampler2D texture1;
uniform bool additiveBlending;
uniform float opacity = 1.0;
uniform bool mirrorBackside = true;
uniform vec3 multiplyColor;
Fragment getFragment() {
@@ -40,7 +41,12 @@ Fragment getFragment() {
frag.color = texture(texture1, vs_st);
}
else {
frag.color = texture(texture1, vec2(1 - vs_st.s, vs_st.t));
if (mirrorBackside) {
frag.color = texture(texture1, vec2(1.0 - vs_st.s, vs_st.t));
}
else {
frag.color = texture(texture1, vs_st);
}
}
frag.color.rgb *= multiplyColor;

View File

@@ -37,14 +37,12 @@
#include <openspace/rendering/transferfunction.h>
#include <atomic>
namespace { enum class SourceFileType; }
namespace openspace {
class RenderableFieldlinesSequence : public Renderable {
public:
RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary);
void initialize() override;
void initializeGL() override;
void deinitializeGL() override;
@@ -53,30 +51,55 @@ public:
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
static documentation::Documentation Documentation();
private:
// ------------------------------------- ENUMS -------------------------------------//
void addStateToSequence(FieldlinesState& STATE);
void computeSequenceEndTime();
void definePropertyCallbackFunctions();
void extractTriggerTimesFromFileNames();
bool loadJsonStatesIntoRAM();
void loadOsflsStatesIntoRAM();
bool getStatesFromCdfFiles();
void setModelDependentConstants();
void setupProperties();
bool prepareForOsflsStreaming();
void readNewState(const std::string& filePath);
void updateActiveTriggerTimeIndex(double currentTime);
void updateVertexPositionBuffer();
void updateVertexColorBuffer();
void updateVertexMaskingBuffer();
// Used to determine if lines should be colored UNIFORMLY or by an extraQuantity
enum class ColorMethod : int {
enum class ColorMethod {
Uniform = 0,
ByQuantity
ByQuantity = 1
};
enum class SourceFileType {
Cdf = 0,
Json = 1,
Osfls = 2
};
// ------------------------------------ STRINGS ------------------------------------//
std::string _identifier; // Name of the Node!
// cdf, osfls or json
SourceFileType _inputFileType;
// Output folder path in case of file conversion
std::string _outputFolderPath;
// which tracing vaiable to trace. 'b' for fieldline is default
std::string _tracingVariable;
// path to directory with seed point files
std::filesystem::path _seedPointDirectory;
// optional except when using json input
std::string _modelStr;
fls::Model thismodel;
// ------------------------------------- FLAGS -------------------------------------//
// Used for 'runtime-states'. True when loading a new state from disk on another
// thread.
std::atomic_bool _isLoadingStateFromDisk = false;
// False => states are stored in RAM (using 'in-RAM-states'), True => states are
// loaded from disk during runtime (using 'runtime-states')
bool _loadingStatesDynamically = false;
// Used for 'runtime-states': True if new 'runtime-state' must be loaded from disk.
// False => the previous frame's state should still be shown
bool _mustLoadNewStateFromDisk = false;
// Used for 'in-RAM-states' : True if new 'in-RAM-state' must be loaded.
// False => the previous frame's state should still be shown
bool _needsUpdate = false;
// Used for 'runtime-states'. True when finished loading a new state from disk on
// another thread.
std::atomic_bool _newStateIsReady = false;
@@ -86,20 +109,22 @@ private:
// line segments
bool _shouldUpdateMaskingBuffer = false;
// --------------------------------- NUMERICALS ----------------------------------- //
// Active index of _states. If(==-1)=>no state available for current time. Always the
// same as _activeTriggerTimeIndex if(_loadingStatesDynamically==true), else
// always = 0
int _activeStateIndex = -1;
// Active index of _startTimes
int _activeTriggerTimeIndex = -1;
// Manual time offset
double _manualTimeOffset = 0.0;
// Number of states in the sequence
size_t _nStates = 0;
// In setup it is used to scale JSON coordinates. During runtime it is used to scale
// domain limits.
float _scalingFactor = 1.f;
// Estimated end of sequence.
double _sequenceEndTime;
// If there's just one state it should never disappear
double _sequenceEndTime = std::numeric_limits<double>::max();
// OpenGL Vertex Array Object
GLuint _vertexArrayObject = 0;
// OpenGL Vertex Buffer Object containing the extraQuantity values used for coloring
@@ -111,16 +136,13 @@ private:
// OpenGL Vertex Buffer Object containing the vertex positions
GLuint _vertexPositionBuffer = 0;
// ----------------------------------- POINTERS ------------------------------------//
// The Lua-Modfile-Dictionary used during initialization
std::unique_ptr<ghoul::Dictionary> _dictionary;
// Used for 'runtime-states' when switching out current state to a new state
std::unique_ptr<FieldlinesState> _newState;
std::unique_ptr<ghoul::opengl::ProgramObject> _shaderProgram;
// Transfer function used to color lines when _pColorMethod is set to BY_QUANTITY
std::unique_ptr<TransferFunction> _transferFunction;
// ------------------------------------ VECTORS ----------------------------------- //
// Paths to color tables. One for each 'extraQuantity'
std::vector<std::string> _colorTablePaths;
// Values represents min & max values represented in the color table
@@ -130,101 +152,73 @@ private:
// Stores the provided source file paths if using 'runtime-states', else emptied after
// initialization
std::vector<std::string> _sourceFiles;
// Extra variables such as rho, p or t
std::vector<std::string> _extraVars;
// Contains the _triggerTimes for all FieldlineStates in the sequence
std::vector<double> _startTimes;
// Stores the FieldlineStates
std::vector<FieldlinesState> _states;
// ---------------------------------- Properties ---------------------------------- //
// Group to hold the color properties
properties::PropertyOwner _pColorGroup;
properties::PropertyOwner _colorGroup;
// Uniform/transfer function/topology?
properties::OptionProperty _pColorMethod;
properties::OptionProperty _colorMethod;
// Index of the extra quantity to color lines by
properties::OptionProperty _pColorQuantity;
// Color table/transfer function min
properties::StringProperty _pColorQuantityMin;
// Color table/transfer function max
properties::StringProperty _pColorQuantityMax;
properties::OptionProperty _colorQuantity;
// Used to save property for later initialization
int _colorQuantityTemp = 0;
// Color table/transfer function min and max range
properties::Vec2Property _colorQuantityMinMax;
// Color table/transfer function for "By Quantity" coloring
properties::StringProperty _pColorTablePath;
properties::StringProperty _colorTablePath;
// Uniform Field Line Color
properties::Vec4Property _pColorUniform;
properties::Vec4Property _colorUniform;
// Whether or not to use additive blending
properties::BoolProperty _pColorABlendEnabled;
properties::BoolProperty _colorABlendEnabled;
// Whether or not to use Domain
properties::BoolProperty _pDomainEnabled;
// Whether or not to use Domain
properties::BoolProperty _domainEnabled;
// Group to hold the Domain properties
properties::PropertyOwner _pDomainGroup;
properties::PropertyOwner _domainGroup;
// Domain Limits along x-axis
properties::Vec2Property _pDomainX;
properties::Vec2Property _domainX;
// Domain Limits along y-axis
properties::Vec2Property _pDomainY;
properties::Vec2Property _domainY;
// Domain Limits along z-axis
properties::Vec2Property _pDomainZ;
properties::Vec2Property _domainZ;
// Domain Limits radially
properties::Vec2Property _pDomainR;
properties::Vec2Property _domainR;
// Simulated particles' color
properties::Vec4Property _pFlowColor;
// Simulated particles' color
properties::Vec4Property _flowColor;
// Toggle flow [ON/OFF]
properties::BoolProperty _pFlowEnabled;
properties::BoolProperty _flowEnabled;
// Group to hold the flow/particle properties
properties::PropertyOwner _pFlowGroup;
properties::PropertyOwner _flowGroup;
// Size of simulated flow particles
properties::IntProperty _pFlowParticleSize;
properties::IntProperty _flowParticleSize;
// Size of simulated flow particles
properties::IntProperty _pFlowParticleSpacing;
properties::IntProperty _flowParticleSpacing;
// Toggle flow direction [FORWARDS/BACKWARDS]
properties::BoolProperty _pFlowReversed;
properties::BoolProperty _flowReversed;
// Speed of simulated flow
properties::IntProperty _pFlowSpeed;
properties::IntProperty _flowSpeed;
// Whether or not to use masking
properties::BoolProperty _pMaskingEnabled;
properties::BoolProperty _maskingEnabled;
// Group to hold the masking properties
properties::PropertyOwner _pMaskingGroup;
// Lower limit for allowed values
properties::StringProperty _pMaskingMin;
// Upper limit for allowed values
properties::StringProperty _pMaskingMax;
properties::PropertyOwner _maskingGroup;
// Lower and upper range limit for allowed values
properties::Vec2Property _maskingMinMax;
// Index of the extra quantity to use for masking
properties::OptionProperty _pMaskingQuantity;
properties::OptionProperty _maskingQuantity;
// used to save property for later initialization
int _maskingQuantityTemp = 0;
// Button which sets camera focus to parent node of the renderable
properties::TriggerProperty _pFocusOnOriginBtn;
// Line width for the line rendering part
properties::FloatProperty _lineWidth;
// Button which executes a time jump to start of sequence
properties::TriggerProperty _pJumpToStartBtn;
// --------------------- FUNCTIONS USED DURING INITIALIZATION --------------------- //
void addStateToSequence(FieldlinesState& STATE);
void computeSequenceEndTime();
void definePropertyCallbackFunctions();
bool extractCdfInfoFromDictionary(std::string& seedFilePath, std::string& tracingVar,
std::vector<std::string>& extraVars);
bool extractJsonInfoFromDictionary(fls::Model& model);
void extractMagnitudeVarsFromStrings(std::vector<std::string>& extraVars,
std::vector<std::string>& extraMagVars);
bool extractMandatoryInfoFromDictionary(SourceFileType& sourceFileType);
void extractOptionalInfoFromDictionary(std::string& outputFolderPath);
void extractOsflsInfoFromDictionary();
bool extractSeedPointsFromFile(const std::string& path,
std::vector<glm::vec3>& outVec);
void extractTriggerTimesFromFileNames();
bool loadJsonStatesIntoRAM(const std::string& outputFolder);
void loadOsflsStatesIntoRAM(const std::string& outputFolder);
bool getStatesFromCdfFiles(const std::string& outputFolder);
void setModelDependentConstants();
void setupProperties();
bool prepareForOsflsStreaming();
// ------------------------- FUNCTIONS USED DURING RUNTIME ------------------------ //
void readNewState(const std::string& filePath);
void updateActiveTriggerTimeIndex(double currentTime);
void updateVertexPositionBuffer();
void updateVertexColorBuffer();
void updateVertexMaskingBuffer();
properties::TriggerProperty _jumpToStartBtn;
};
} // namespace openspace

View File

@@ -136,7 +136,6 @@ bool FieldlinesState::loadStateFromOsfls(const std::string& pathToOsflsFile) {
bool FieldlinesState::loadStateFromJson(const std::string& pathToJsonFile,
fls::Model Model, float coordToMeters)
{
// --------------------- ENSURE FILE IS VALID, THEN PARSE IT --------------------- //
std::ifstream ifs(pathToJsonFile);

View File

@@ -26,6 +26,7 @@
#include <modules/fieldlinessequence/util/commons.h>
#include <modules/fieldlinessequence/util/fieldlinesstate.h>
#include <openspace/util/spicemanager.h>
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
#include <memory>
@@ -88,12 +89,13 @@ namespace openspace::fls {
* vector at each line vertex
*/
bool convertCdfToFieldlinesState(FieldlinesState& state, const std::string& cdfPath,
const std::vector<glm::vec3>& seedPoints,
const std::unordered_map<std::string,
std::vector<glm::vec3>>& seedMap,
double manualTimeOffset,
const std::string& tracingVar,
std::vector<std::string>& extraVars,
std::vector<std::string>& extraMagVars)
{
#ifndef OPENSPACE_MODULE_KAMELEON_ENABLED
LERROR("CDF inputs provided but Kameleon module is deactivated");
return false;
@@ -104,9 +106,18 @@ bool convertCdfToFieldlinesState(FieldlinesState& state, const std::string& cdfP
);
state.setModel(fls::stringToModel(kameleon->getModelName()));
state.setTriggerTime(kameleonHelper::getTime(kameleon.get()));
double cdfDoubleTime = kameleonHelper::getTime(kameleon.get(), manualTimeOffset);
state.setTriggerTime(cdfDoubleTime);
if (addLinesToState(kameleon.get(), seedPoints, tracingVar, state)) {
// get time as string.
std::string cdfStringTime = SpiceManager::ref().dateFromEphemerisTime(
cdfDoubleTime, "YYYYMMDDHRMNSC::RND"
);
// use time as string for picking seedpoints from seedm
std::vector<glm::vec3> seedPoints = seedMap.at(cdfStringTime);
bool success = addLinesToState(kameleon.get(), seedPoints, tracingVar, state);
if (success) {
// The line points are in their RAW format (unscaled & maybe spherical)
// Before we scale to meters (and maybe cartesian) we must extract
// the extraQuantites, as the iterpolator needs the unaltered positions
@@ -301,7 +312,9 @@ void prepareStateAndKameleonForExtras(ccmc::Kameleon* kameleon,
std::string& str = extraScalarVars[i];
bool success = kameleon->doesVariableExist(str) && kameleon->loadVariable(str);
if (!success &&
(model == fls::Model::Batsrus && (str == TAsPOverRho || str == "T")))
(model == fls::Model::Batsrus &&
(str == TAsPOverRho || str == "T" || str == "t"))
)
{
LDEBUG(
"BATSRUS doesn't contain variable T for temperature. Trying to calculate "

View File

@@ -36,7 +36,8 @@ class FieldlinesState;
namespace fls {
bool convertCdfToFieldlinesState(FieldlinesState& state, const std::string& cdfPath,
const std::vector<glm::vec3>& seedPoints, const std::string& tracingVar,
const std::unordered_map<std::string, std::vector<glm::vec3>>& seedMap,
double manualTimeOffset, const std::string& tracingVar,
std::vector<std::string>& extraVars, std::vector<std::string>& extraMagVars);
} // namespace fls

View File

@@ -39,7 +39,7 @@ namespace openspace::kameleonHelper {
* \return \c nullptr if the file fails to open
*/
std::unique_ptr<ccmc::Kameleon> createKameleonObject(const std::string& cdfFilePath);
double getTime(ccmc::Kameleon* kameleon);
double getTime(ccmc::Kameleon* kameleon, double manualOffset);
} //namespace openspace::kameleonHelper

View File

@@ -69,97 +69,97 @@ std::unique_ptr<ccmc::Kameleon> createKameleonObject(const std::string& cdfFileP
* *NOTE!* The function has only been tested for some BATSRUS and ENLIL and may need to
* be updated to work with other models!
*/
double getTime(ccmc::Kameleon* kameleon) {
double getTime(ccmc::Kameleon* kameleon, double manualOffset) {
// Inspiration from 'void KameleonInterpolator::setEphemTime()' which doesn't seem to
// exist in the version of Kameleon that is included in OpenSpace. Alterations
// done to fit here.
// As a new version of Kameleon is included in OpenSpace this function may prove to be
// redundant!
std::string seqStartStr;
if (kameleon->doesAttributeExist("start_time")){
seqStartStr =
kameleon->getGlobalAttribute("start_time").getAttributeString();
}
else if (kameleon->doesAttributeExist("tim_rundate_cal")) {
seqStartStr =
kameleon->getGlobalAttribute("tim_rundate_cal").getAttributeString();
const size_t N_CHARS = seqStartStr.length();
if (N_CHARS < 19) {
// Fall through to add the required characters
switch (N_CHARS) {
case 10: // YYYY-MM-DD => YYYY-MM-DDTHH
seqStartStr += "T00";
[[fallthrough]];
case 13: // YYYY-MM-DDTHH => YYYY-MM-DDTHH:
seqStartStr += ":";
[[fallthrough]];
case 14: // YYYY-MM-DDTHH: => YYYY-MM-DDTHH:MM
seqStartStr += "00";
[[fallthrough]];
case 16: // YYYY-MM-DDTHH:MM => YYYY-MM-DDTHH:MM:
seqStartStr += ":";
[[fallthrough]];
case 17: // YYYY-MM-DDTHH:MM: => YYYY-MM-DDTHH:MM:SS
seqStartStr += "00";
[[fallthrough]];
// case 19 : // YYYY-MM-DDTHH:MM:SS => YYYY-MM-DDTHH:MM:SS.000
// seqStartStr += ".000";
// case 23 : // YYYY-MM-DDTHH:MM:SS. => YYYY-MM-DDTHH:MM:SS.000Z
// seqStartStr += "Z";
default:
break;
}
std::string seqStartStr;
if (kameleon->doesAttributeExist("start_time")){
seqStartStr =
kameleon->getGlobalAttribute("start_time").getAttributeString();
}
else if (kameleon->doesAttributeExist("tim_rundate_cal")) {
seqStartStr =
kameleon->getGlobalAttribute("tim_rundate_cal").getAttributeString();
const size_t N_CHARS = seqStartStr.length();
if (N_CHARS < 19) {
// Fall through to add the required characters
switch (N_CHARS) {
case 10: // YYYY-MM-DD => YYYY-MM-DDTHH
seqStartStr += "T00";
[[fallthrough]];
case 13: // YYYY-MM-DDTHH => YYYY-MM-DDTHH:
seqStartStr += ":";
[[fallthrough]];
case 14: // YYYY-MM-DDTHH: => YYYY-MM-DDTHH:MM
seqStartStr += "00";
[[fallthrough]];
case 16: // YYYY-MM-DDTHH:MM => YYYY-MM-DDTHH:MM:
seqStartStr += ":";
[[fallthrough]];
case 17: // YYYY-MM-DDTHH:MM: => YYYY-MM-DDTHH:MM:SS
seqStartStr += "00";
[[fallthrough]];
// case 19 : // YYYY-MM-DDTHH:MM:SS => YYYY-MM-DDTHH:MM:SS.000
// seqStartStr += ".000";
// case 23 : // YYYY-MM-DDTHH:MM:SS. => YYYY-MM-DDTHH:MM:SS.000Z
// seqStartStr += "Z";
default:
break;
}
}
else if (kameleon->doesAttributeExist("tim_obsdate_cal")) {
seqStartStr =
kameleon->getGlobalAttribute("tim_obsdate_cal").getAttributeString();
}
else if (kameleon->doesAttributeExist("tim_crstart_cal")) {
seqStartStr =
kameleon->getGlobalAttribute("tim_crstart_cal").getAttributeString();
}
else {
LWARNING(
"No starting time attribute could be found in the .cdf file. Starting "
"time is set to 01.JAN.2000 12:00."
);
}
}
else if (kameleon->doesAttributeExist("tim_obsdate_cal")) {
seqStartStr =
kameleon->getGlobalAttribute("tim_obsdate_cal").getAttributeString();
}
else if (kameleon->doesAttributeExist("tim_crstart_cal")) {
seqStartStr =
kameleon->getGlobalAttribute("tim_crstart_cal").getAttributeString();
}
else {
LWARNING(
"No starting time attribute could be found in the .cdf file. Starting "
"time is set to 01.JAN.2000 12:00."
);
}
if (seqStartStr.length() == 19) {
seqStartStr += ".000Z";
}
if (seqStartStr.length() == 19) {
seqStartStr += ".000Z";
}
double seqStartDbl;
if (seqStartStr.length() == 24) {
seqStartDbl = Time::convertTime(
seqStartStr.substr(0, seqStartStr.length() - 2)
);
}
else {
LWARNING("No starting time attribute could be found in the .cdf file."
"Starting time is set to 01.JAN.2000 12:00.");
seqStartDbl = 0.0;
}
double seqStartDbl;
if (seqStartStr.length() == 24) {
seqStartDbl = Time::convertTime(
seqStartStr.substr(0, seqStartStr.length() - 2)
);
}
else {
LWARNING("No starting time attribute could be found in the .cdf file."
"Starting time is set to 01.JAN.2000 12:00.");
seqStartDbl = 0.0;
}
double stateStartOffset;
double stateStartOffset;
if (kameleon->doesAttributeExist("elapsed_time_in_seconds")) {
ccmc::Attribute att = kameleon->getGlobalAttribute("elapsed_time_in_seconds");
stateStartOffset = static_cast<double>(att.getAttributeFloat());
}
else if (kameleon->doesAttributeExist("time_physical_time")) {
ccmc::Attribute att = kameleon->getGlobalAttribute("time_physical_time");
stateStartOffset = static_cast<double>(att.getAttributeFloat());
}
else {
stateStartOffset = 0.0;
LWARNING("No time offset attribute could be found in the .cdf file."
"The current state starts the same time as the sequence!");
}
if (kameleon->doesAttributeExist("elapsed_time_in_seconds")) {
ccmc::Attribute att = kameleon->getGlobalAttribute("elapsed_time_in_seconds");
stateStartOffset = static_cast<double>(att.getAttributeFloat());
}
else if (kameleon->doesAttributeExist("time_physical_time")) {
ccmc::Attribute att = kameleon->getGlobalAttribute("time_physical_time");
stateStartOffset = static_cast<double>(att.getAttributeFloat());
}
else {
stateStartOffset = 0.0;
LWARNING("No time offset attribute could be found in the .cdf file."
"The current state starts the same time as the sequence!");
}
return seqStartDbl + stateStartOffset;
return seqStartDbl + stateStartOffset + manualOffset;
}
} // namespace openspace::kameleonHelper {

View File

@@ -28,12 +28,14 @@ set(HEADER_FILES
speckloader.h
rendering/planetgeometry.h
rendering/renderableconstellationbounds.h
rendering/renderablefluxnodes.h
rendering/renderablehabitablezone.h
rendering/renderablerings.h
rendering/renderableorbitalkepler.h
rendering/renderablesatellites.h
rendering/renderablesmallbody.h
rendering/renderablestars.h
rendering/renderabletravelspeed.h
rendering/simplespheregeometry.h
translation/keplertranslation.h
translation/spicetranslation.h
@@ -48,12 +50,14 @@ set(SOURCE_FILES
speckloader.cpp
rendering/planetgeometry.cpp
rendering/renderableconstellationbounds.cpp
rendering/renderablefluxnodes.cpp
rendering/renderablehabitablezone.cpp
rendering/renderablerings.cpp
rendering/renderableorbitalkepler.cpp
rendering/renderablesatellites.cpp
rendering/renderablesmallbody.cpp
rendering/renderablestars.cpp
rendering/renderabletravelspeed.cpp
rendering/simplespheregeometry.cpp
translation/keplertranslation.cpp
translation/spicetranslation.cpp
@@ -68,6 +72,8 @@ set(SHADER_FILES
shaders/constellationbounds_vs.glsl
shaders/debrisViz_fs.glsl
shaders/debrisViz_vs.glsl
shaders/fluxnodes_fs.glsl
shaders/fluxnodes_vs.glsl
shaders/habitablezone_vs.glsl
shaders/habitablezone_fs.glsl
shaders/rings_vs.glsl
@@ -75,6 +81,8 @@ set(SHADER_FILES
shaders/star_fs.glsl
shaders/star_ge.glsl
shaders/star_vs.glsl
shaders/travelspeed_fs.glsl
shaders/travelspeed_vs.glsl
)
source_group("Shader Files" FILES ${SHADER_FILES})

View File

@@ -0,0 +1,856 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include <modules/space/rendering/renderablefluxnodes.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/updatestructures.h>
#include <openspace/query/query.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/logging/consolelog.h>
#include <ghoul/logging/visualstudiooutputlog.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/textureunit.h>
#include <fstream>
#include <functional>
#include <optional>
#include <sys/stat.h>
#include <thread>
namespace {
constexpr const char* _loggerCat = "RenderableFluxNodes";
constexpr const std::array<const char*, 29> UniformNames = {
"streamColor", "nodeSize", "proximityNodesSize",
"thresholdFlux", "colorMode", "filterLower", "filterUpper", "scalingMode",
"colorTableRange", "domainLimZ", "nodeSkip", "nodeSkipDefault", "nodeSkipEarth",
"nodeSkipMethod", "nodeSkipFluxThreshold", "nodeSkipRadiusThreshold",
"fluxColorAlpha", "earthPos", "distanceThreshold", "time", "maxNodeDistanceSize",
"usingCameraPerspective", "drawCircles", "drawHollow", "useGaussian",
"perspectiveDistanceFactor", "minMaxNodeSize", "usingPulse",
"usingGaussianPulse"
};
constexpr openspace::properties::Property::PropertyInfo GoesEnergyBinsInfo = {
"GoesEnergy",
"GOES Energy",
"Select which energy bin you want to show. GOES = Geostationary Operational "
"Environmental Satellites. Emin01 is values > 10 MeV, "
"Default is Emin03 where values > 100 MeV."
};
constexpr openspace::properties::Property::PropertyInfo ColorModeInfo = {
"ColorMode",
"Color Mode",
"Color lines uniformly or using color tables based on specific values on nodes, "
"for examples flux values."
};
constexpr openspace::properties::Property::PropertyInfo ColorTablePathInfo = {
"ColorTablePath",
"Path to Color Table",
"Color Table/Transfer Function to use for 'By Flux Value' coloring."
};
constexpr openspace::properties::Property::PropertyInfo StreamColorInfo = {
"Color",
"Color",
"Color of particles."
};
constexpr openspace::properties::Property::PropertyInfo NodeSizeInfo = {
"NodeSize",
"Size of nodes",
"Change the size of the rendered points of the nodes"
};
constexpr openspace::properties::Property::PropertyInfo ThresholdFluxInfo = {
"ThresholdFlux",
"Threshold flux value",
"This value specifies the threshold that will be changed with the flux value."
};
constexpr openspace::properties::Property::PropertyInfo FilteringInfo = {
"FilterLower",
"Filtering Lower Value in AU",
"Use filtering to show nodes within a given range."
};
constexpr openspace::properties::Property::PropertyInfo FilteringUpperInfo = {
"FilterUpper",
"Filtering Upper Value in AU",
"Use filtering to show nodes within a given range."
};
constexpr openspace::properties::Property::PropertyInfo AmountofNodesInfo = {
"AmountOfNodes",
"Every nth node to render in",
"Show only every nth node"
};
constexpr openspace::properties::Property::PropertyInfo DefaultNodeSkipInfo = {
"NodeSkip",
"Every nth node to render default",
"Show only every nth node outside of skippingmethod"
};
constexpr openspace::properties::Property::PropertyInfo EarthNodeSkipInfo = {
"NodeSkipEarth",
"Every nth node to render close to Earth",
"Show only every nth node outside of skippingmethod"
};
constexpr openspace::properties::Property::PropertyInfo ScalingmethodInfo = {
"ScalingFlux",
"Scale the flux value with color table",
"Use scaling to color nodes with a given method."
};
constexpr openspace::properties::Property::PropertyInfo NodeskipMethodInfo = {
"SkippingNodes",
"How to select nodes to skip",
"Methods to select nodes to skip."
};
constexpr openspace::properties::Property::PropertyInfo colorTableRangeInfo = {
"ColorTableRange",
"Color Table Range",
"Valid range for the color table as the exponent, with base 10, of flux values. "
"[Min, Max]"
};
constexpr openspace::properties::Property::PropertyInfo DomainZInfo = {
"ZLimit",
"Z-limits",
"Valid range along the Z-axis. [Min, Max]"
};
constexpr openspace::properties::Property::PropertyInfo FluxColorAlphaInfo = {
"FluxColorAlpha",
"Flux Color Alpha",
"The value of alpha for the flux color mode."
};
constexpr openspace::properties::Property::PropertyInfo FluxNodeskipThresholdInfo = {
"SkippingNodesByFlux",
"Skipping Nodes By Flux",
"Select nodes to skip depending on flux value."
};
constexpr openspace::properties::Property::PropertyInfo
RadiusNodeSkipThresholdInfo = {
"SkippingNodesByRadius",
"Skipping Nodes By Radius",
"Select nodes to skip depending on Radius."
};
constexpr openspace::properties::Property::PropertyInfo DistanceplanetInfo = {
"Distanceplanet",
"Distance Planet",
"Deciding what planet to check distance to."
};
constexpr openspace::properties::Property::PropertyInfo DistanceThresholdInfo = {
"DistancePlanetThreshold",
"Threshold for distance between planet",
"Changes threshold distance for highlighting nodes close to earth."
};
constexpr openspace::properties::Property::PropertyInfo ProximityNodesSizeInfo = {
"ProximityNodesSize",
"Earths Proximity Nodes Size",
"Changes size of nodes only close to earth."
};
constexpr openspace::properties::Property::PropertyInfo MisalignedIndexInfo = {
"MisalignedIndex",
"Index to shift sequence number",
"The misalignment number for sequence for fluxnodes vs Fieldlines"
};
constexpr openspace::properties::Property::PropertyInfo MaxNodeDistanceSizeInfo = {
"MaxNodeDistanceSize",
"Max Node Distance Size",
"The maximum size of the nodes at a certin distance."
};
constexpr openspace::properties::Property::PropertyInfo
CameraPerspectiveEnabledInfo = {
"CameraPerspectiveEnabled",
"Use Camera perspective",
"Camera perspective changes the size of the nodes dependent on the "
"distance from camera."
};
constexpr openspace::properties::Property::PropertyInfo DrawingCirclesInfo = {
"RenderingCircles",
"Render as circles",
"Using fragment shader to draw nodes as circles instead of squares."
};
constexpr openspace::properties::Property::PropertyInfo DrawingHollowInfo = {
"RenderingHollowCircles",
"Render as hollow circles",
"Using fragment shader to draw nodes as hollow circles."
};
constexpr openspace::properties::Property::PropertyInfo GaussiandAlphaFilterInfo = {
"RenderingGaussianAlphaFilter",
"Alpha by Gaussian",
"Using fragment shader to draw nodes with Gaussian filter for alpha value."
};
constexpr openspace::properties::Property::PropertyInfo
PerspectiveDistanceFactorInfo = {
"PerspectiveDistanceFactor",
"Perspective Distance factor",
"This value decides how far away the camera must be to start "
"impacting the node size."
};
constexpr openspace::properties::Property::PropertyInfo MinMaxNodeSizeInfo = {
"MinMaxNodeSize",
"Min & Max node size",
"The minimum and maximum node size."
};
constexpr openspace::properties::Property::PropertyInfo pulseEnabledInfo = {
"PulseEnabled",
"Nodes close to Earth pulsate",
"Toggles the pulse for nodes close to Earth."
};
constexpr openspace::properties::Property::PropertyInfo gaussianPulseEnabledInfo = {
"GaussianPulseEnabled",
"Nodes close to Earth pulsate with alpha by gaussian",
"Toggles the pulse with alpha by gaussian for nodes close to Earth."
};
struct [[codegen::Dictionary(RenderableFluxNodes)]] Parameters {
// path to source folder with the 3 binary files in it
std::filesystem::path sourceFolder [[codegen::directory()]];
// [[codegen::verbatim(ColorTablePathInfo.description)]]
std::string colorTablePath;
// [[codegen::verbatim(GoesEnergyBinsInfo.description)]]
std::optional<int> energyBin;
// [[codegen::verbatim(colorTableRangeInfo.description)]]
std::optional<glm::vec2> colorTableRange;
};
#include "renderablefluxnodes_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation RenderableFluxNodes::Documentation() {
return codegen::doc<Parameters>("space_renderable_flux_nodes");
}
RenderableFluxNodes::RenderableFluxNodes(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _goesEnergyBins(GoesEnergyBinsInfo, properties::OptionProperty::DisplayType::Radio)
, _styleGroup({ "Style" })
, _colorMode(ColorModeInfo, properties::OptionProperty::DisplayType::Radio)
, _scalingMethod(ScalingmethodInfo, properties::OptionProperty::DisplayType::Radio)
, _nodeskipMethod(NodeskipMethodInfo, properties::OptionProperty::DisplayType::Radio)
, _streamColor(
StreamColorInfo,
glm::vec4(0.96f, 0.88f, 0.8f, 1.f),
glm::vec4(0.f),
glm::vec4(1.f))
, _streamGroup({ "Streams" })
, _nodesAmountGroup({ "NodeGroup" })
, _nodeSize(NodeSizeInfo, 2.f, 1.f, 10.f)
, _colorTablePath(ColorTablePathInfo)
, _colorTableRange(colorTableRangeInfo, { -2.f, 4.f }, { -8.f, -8.f }, { 8.f, 8.f })
, _domainZ(DomainZInfo, { -2.5f, 2.5f }, { -2.5f, -2.5f }, { 2.5f, 2.5f})
, _fluxColorAlpha(FluxColorAlphaInfo, 1.f, 0.f, 1.f)
, _thresholdFlux(ThresholdFluxInfo, -1.5f, -50.f, 10.f)
, _filteringLower(FilteringInfo, 0.f, 0.f, 5.f)
, _filteringUpper(FilteringUpperInfo, 5.f, 0.f, 5.f)
, _amountofNodes(AmountofNodesInfo, 1, 1, 100)
, _defaultNodeSkip(DefaultNodeSkipInfo, 1, 1, 100)
, _earthNodeSkip(EarthNodeSkipInfo, 1, 1, 100)
, _fluxNodeskipThreshold(FluxNodeskipThresholdInfo, 0, -20, 10)
, _radiusNodeSkipThreshold(RadiusNodeSkipThresholdInfo, 0.f, 0.f, 5.f)
, _earthdistGroup({ "Earthfocus" })
, _distanceThreshold(DistanceThresholdInfo, 0.f, 0.f, 1.f)
, _proximityNodesSize(ProximityNodesSizeInfo, 1.f, 0.f, 100.f)
, _maxNodeDistanceSize(MaxNodeDistanceSizeInfo, 1.f, 1.f, 10.f)
, _cameraPerspectiveEnabled(CameraPerspectiveEnabledInfo, false)
, _drawingCircles(DrawingCirclesInfo, true)
, _cameraPerspectiveGroup({ "CameraPerspective" })
, _drawingHollow(DrawingHollowInfo, false)
, _gaussianAlphaFilter(GaussiandAlphaFilterInfo, false)
, _perspectiveDistanceFactor(PerspectiveDistanceFactorInfo, 2.67f, 1.f, 20.f)
, _minMaxNodeSize(MinMaxNodeSizeInfo, {2.f, 30.f}, {1.f, 1.f}, {10.f, 200.f})
, _pulseEnabled(pulseEnabledInfo, false)
, _gaussianPulseEnabled(gaussianPulseEnabledInfo, false)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
_colorTablePath = p.colorTablePath;
_transferFunction = std::make_unique<TransferFunction>(_colorTablePath);
_colorTableRange = p.colorTableRange.value_or(_colorTableRange);
_binarySourceFolderPath = p.sourceFolder;
if (std::filesystem::is_directory(_binarySourceFolderPath)) {
// Extract all file paths from the provided folder
namespace fs = std::filesystem;
for (const fs::directory_entry& e :
fs::directory_iterator(_binarySourceFolderPath))
{
if (e.is_regular_file()) {
_binarySourceFiles.push_back(e.path().string());
}
}
std::sort(_binarySourceFiles.begin(), _binarySourceFiles.end());
// Ensure that there are available and valid source files left
if (_binarySourceFiles.empty()) {
LERROR(fmt::format("{} contains no files", _binarySourceFolderPath));
}
}
else {
LERROR(fmt::format("Source folder {} is not a valid directory",
_binarySourceFolderPath
));
}
_goesEnergyBins.addOption(static_cast<int>(GoesEnergyBins::Emin01), "Emin01");
_goesEnergyBins.addOption(static_cast<int>(GoesEnergyBins::Emin03), "Emin03");
_colorMode.addOption(static_cast<int>(ColorMethod::ByFluxValue), "By Flux Value");
_colorMode.addOption(static_cast<int>(ColorMethod::Uniform), "Uniform");
_scalingMethod.addOption(static_cast<int>(ScalingMethod::Flux), "Flux");
_scalingMethod.addOption(static_cast<int>(ScalingMethod::RFlux), "Radius * Flux");
_scalingMethod.addOption(static_cast<int>(ScalingMethod::R2Flux), "Radius^2 * Flux");
_scalingMethod.addOption(
static_cast<int>(ScalingMethod::Log10RFlux), "log10(r) * Flux"
);
_scalingMethod.addOption(static_cast<int>(ScalingMethod::LnRFlux), "ln(r) * Flux");
_nodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Uniform), "Uniform");
_nodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Flux), "Flux");
_nodeskipMethod.addOption(static_cast<int>(NodeSkipMethod::Radius), "Radius");
if (p.energyBin.has_value()) {
_goesEnergyBins.setValue(p.energyBin.value());
}
else { // default int 1 == Emin03 == MeV>100
LINFO("Assuming default value 1, meaning Emin03");
_goesEnergyBins.setValue(1);
}
}
void RenderableFluxNodes::initialize() {
populateStartTimes();
loadNodeData(_goesEnergyBins.option().value);
computeSequenceEndTime();
}
void RenderableFluxNodes::initializeGL() {
// Setup shader program
_shaderProgram = global::renderEngine->buildRenderProgram(
"Fluxnodes",
absPath("${MODULE_SPACE}/shaders/fluxnodes_vs.glsl"),
absPath("${MODULE_SPACE}/shaders/fluxnodes_fs.glsl")
);
_uniformCache.streamColor = _shaderProgram->uniformLocation("streamColor");
_uniformCache.nodeSize = _shaderProgram->uniformLocation("nodeSize");
_uniformCache.thresholdFlux = _shaderProgram->uniformLocation("thresholdFlux");
ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache, UniformNames);
glGenVertexArrays(1, &_vertexArrayObject);
glGenBuffers(1, &_vertexPositionBuffer);
glGenBuffers(1, &_vertexColorBuffer);
glGenBuffers(1, &_vertexFilteringBuffer);
// Needed for alpha transparency
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
setupProperties();
}
void RenderableFluxNodes::definePropertyCallbackFunctions() {
// Add Property Callback Functions
_goesEnergyBins.onChange([this] {
loadNodeData(_goesEnergyBins.option().value);
});
_colorTablePath.onChange([this]() {
_transferFunction->setPath(_colorTablePath);
});
}
void RenderableFluxNodes::loadNodeData(int energybinOption) {
LDEBUG("Loading in binary files directly from sync folder");
std::string energybin;
switch (energybinOption) {
case 0:
energybin = "_emin01";
break;
case 1:
energybin = "_emin03";
break;
}
std::string file = _binarySourceFolderPath.string() + "\\positions" + energybin;
std::string file2 = _binarySourceFolderPath.string() + "\\fluxes" + energybin;
std::string file3 = _binarySourceFolderPath.string() + "\\radiuses" + energybin;
std::ifstream fileStream(file, std::ifstream::binary);
std::ifstream fileStream2(file2, std::ifstream::binary);
std::ifstream fileStream3(file3, std::ifstream::binary);
if (!fileStream.good()) {
LERROR(fmt::format("Could not read file '{}'", file));
return;
}
uint32_t nNodesPerTimestep = 0;
fileStream.read(reinterpret_cast<char*>(&nNodesPerTimestep), sizeof(uint32_t));
uint32_t nTimeSteps = 0;
fileStream.read(reinterpret_cast<char*>(&nTimeSteps), sizeof(uint32_t));
_nStates = nTimeSteps;
if (_nStates != _startTimes.size()) {
LERROR(
"Number of states, _nStates, and number of start times, _startTimes, "
"do not match"
);
return;
}
_statesColor.clear();
_statesPos.clear();
_statesRadius.clear();
for (unsigned int i = 0; i < _nStates; ++i) {
_vertexPositions.resize(nNodesPerTimestep);
fileStream.read(reinterpret_cast<char*>(
_vertexPositions.data()), nNodesPerTimestep * sizeof(glm::vec3)
);
_statesPos.push_back(_vertexPositions);
_vertexPositions.clear();
}
for (unsigned int i = 0; i < _nStates; ++i) {
_vertexColor.resize(nNodesPerTimestep);
fileStream2.read(reinterpret_cast<char*>(
_vertexColor.data()), nNodesPerTimestep * sizeof(float)
);
_statesColor.push_back(_vertexColor);
_vertexColor.clear();
}
for (unsigned int i = 0; i < _nStates; ++i) {
_vertexRadius.resize(nNodesPerTimestep);
fileStream3.read(reinterpret_cast<char*>(
_vertexRadius.data()), nNodesPerTimestep * sizeof(float)
);
_statesRadius.push_back(_vertexRadius);
_vertexRadius.clear();
}
}
void RenderableFluxNodes::setupProperties() {
addProperty(_goesEnergyBins);
addPropertySubOwner(_styleGroup);
addPropertySubOwner(_streamGroup);
addPropertySubOwner(_nodesAmountGroup);
addPropertySubOwner(_earthdistGroup);
addPropertySubOwner(_cameraPerspectiveGroup);
_cameraPerspectiveGroup.addProperty(_cameraPerspectiveEnabled);
_cameraPerspectiveGroup.addProperty(_perspectiveDistanceFactor);
_minMaxNodeSize.setViewOption(properties::Property::ViewOptions::MinMaxRange);
_cameraPerspectiveGroup.addProperty(_minMaxNodeSize);
_earthdistGroup.addProperty(_distanceThreshold);
_earthdistGroup.addProperty(_proximityNodesSize);
_earthdistGroup.addProperty(_pulseEnabled);
_earthdistGroup.addProperty(_gaussianPulseEnabled);
_nodesAmountGroup.addProperty(_nodeskipMethod);
_nodesAmountGroup.addProperty(_amountofNodes);
_nodesAmountGroup.addProperty(_defaultNodeSkip);
_nodesAmountGroup.addProperty(_earthNodeSkip);
_nodesAmountGroup.addProperty(_nodeSize);
_nodesAmountGroup.addProperty(_fluxNodeskipThreshold);
_nodesAmountGroup.addProperty(_radiusNodeSkipThreshold);
_nodesAmountGroup.addProperty(_maxNodeDistanceSize);
_streamGroup.addProperty(_thresholdFlux);
_streamGroup.addProperty(_filteringLower);
_streamGroup.addProperty(_filteringUpper);
_streamGroup.addProperty(_domainZ);
_styleGroup.addProperty(_drawingCircles);
_styleGroup.addProperty(_drawingHollow);
_styleGroup.addProperty(_gaussianAlphaFilter);
_styleGroup.addProperty(_colorMode);
_styleGroup.addProperty(_scalingMethod);
_colorTableRange.setViewOption(properties::Property::ViewOptions::MinMaxRange);
_styleGroup.addProperty(_colorTableRange);
_styleGroup.addProperty(_colorTablePath);
_styleGroup.addProperty(_streamColor);
_styleGroup.addProperty(_fluxColorAlpha);
definePropertyCallbackFunctions();
}
void RenderableFluxNodes::deinitializeGL() {
glDeleteVertexArrays(1, &_vertexArrayObject);
_vertexArrayObject = 0;
glDeleteBuffers(1, &_vertexPositionBuffer);
_vertexPositionBuffer = 0;
glDeleteBuffers(1, &_vertexColorBuffer);
_vertexColorBuffer = 0;
glDeleteBuffers(1, &_vertexFilteringBuffer);
_vertexFilteringBuffer = 0;
if (_shaderProgram) {
global::renderEngine->removeRenderProgram(_shaderProgram.get());
_shaderProgram = nullptr;
}
}
bool RenderableFluxNodes::isReady() const {
return _shaderProgram != nullptr;
}
void RenderableFluxNodes::populateStartTimes() {
// number of characters in UTC ISO8601 format (without additional Z)
// 'YYYY-MM-DDTHH-MM-SS-XXX'
constexpr const int timeFormatSize = 23;
std::string timeFile;
std::string fileType;
for (const std::string& filePath : _binarySourceFiles) {
timeFile = filePath;
if (filePath.substr(filePath.find_last_of(".") + 1) == "csv") {
fileType = "csv";
break;
}
else if (filePath.substr(filePath.find_last_of(".") + 1) == "dat") {
fileType = "dat";
break;
}
else if (filePath.substr(filePath.find_last_of(".") + 1) == "txt") {
fileType = "txt";
break;
}
//if no file extention but word "time" in file name
else if (filePath.find("time") != std::string::npos &&
filePath.find(".") == std::string::npos)
{
break;
}
else {
LERROR(fmt::format("Error in file type or naming of file '{}'. ",
"Time meta file supports csv, dat, txt or without file extention ",
"(but then have to include 'time' in filename)", filePath
));
timeFile.clear();
}
}
if (timeFile.empty()) {
LERROR(
"Could not find a metadata file with time steps, "
"such as a csv, dat, txt or no file extention with 'time' in filename"
);
}
// time filestream
std::ifstream tfs(timeFile);
if (!tfs.is_open()) {
throw ghoul::RuntimeError("Could not open file");
}
std::string line;
// gets only first line to "remove" header
std::getline(tfs, line);
std::stringstream s;
s << line;
int nColumns = 0;
std::string columnName;
// loops through the names/columns in first line/header
while (s >> columnName) {
++nColumns;
}
while (std::getline(tfs, line)) { // for each line of data
std::istringstream iss(line);
for (int i = 0; i < nColumns; ++i) { // for each column in line
std::string columnValue;
iss >> columnValue;
if (i != nColumns - 1) { // last column
continue;
}
if (columnValue.length() == 23) {
// Ensure the separators are correct
columnValue.replace(4, 1, "-");
columnValue.replace(7, 1, "-");
columnValue.replace(13, 1, ":");
columnValue.replace(16, 1, ":");
columnValue.replace(19, 1, ".");
const double triggerTime = Time::convertTime(columnValue);
_startTimes.push_back(triggerTime);
}
else {
LERROR(fmt::format("Error in file formating. Last column in ",
"file '{}' is not on UTC ISO8601 format", timeFile
));
}
}
}
}
void RenderableFluxNodes::updateActiveTriggerTimeIndex(double currentTime) {
auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), currentTime);
if (iter != _startTimes.end()) {
if (iter != _startTimes.begin()) {
std::ptrdiff_t idx = std::distance(_startTimes.begin(), iter);
_activeTriggerTimeIndex = static_cast<int>(idx) - 1;
}
else {
_activeTriggerTimeIndex = 0;
}
}
else {
_activeTriggerTimeIndex = static_cast<int>(_nStates) - 1;
}
}
void RenderableFluxNodes::render(const RenderData& data, RendererTasks&) {
if (_activeTriggerTimeIndex == -1) {
return;
}
_shaderProgram->activate();
// Calculate Model View MatrixProjection
const glm::dmat4 rotMat = glm::dmat4(data.modelTransform.rotation);
const glm::dmat4 modelMat =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
rotMat *
glm::dmat4(glm::scale(
glm::dmat4(1.0), data.modelTransform.scale
));
const glm::dmat4 modelViewMat = data.camera.combinedViewMatrix() * modelMat;
_shaderProgram->setUniform("modelViewProjection",
data.camera.sgctInternal.projectionMatrix() * glm::mat4(modelViewMat)
);
SceneGraphNode* earthNode = sceneGraphNode("Earth");
if (!earthNode) {
LWARNING("Could not find scene graph node 'Earth'");
}
glm::vec3 earthPos = earthNode->worldPosition() * data.modelTransform.rotation;
_shaderProgram->setUniform(_uniformCache.streamColor, _streamColor);
_shaderProgram->setUniform(_uniformCache.nodeSize, _nodeSize);
_shaderProgram->setUniform(_uniformCache.thresholdFlux, _thresholdFlux);
_shaderProgram->setUniform(_uniformCache.colorMode, _colorMode);
_shaderProgram->setUniform(_uniformCache.filterLower, _filteringLower);
_shaderProgram->setUniform(_uniformCache.filterUpper, _filteringUpper);
_shaderProgram->setUniform(_uniformCache.scalingMode, _scalingMethod);
_shaderProgram->setUniform(_uniformCache.colorTableRange, _colorTableRange);
_shaderProgram->setUniform(_uniformCache.domainLimZ, _domainZ);
_shaderProgram->setUniform(_uniformCache.nodeSkip, _amountofNodes);
_shaderProgram->setUniform(_uniformCache.nodeSkipDefault, _defaultNodeSkip);
_shaderProgram->setUniform(_uniformCache.nodeSkipEarth, _earthNodeSkip);
_shaderProgram->setUniform(_uniformCache.nodeSkipMethod, _nodeskipMethod);
_shaderProgram->setUniform(
_uniformCache.nodeSkipFluxThreshold,
_fluxNodeskipThreshold
);
_shaderProgram->setUniform(
_uniformCache.nodeSkipRadiusThreshold,
_radiusNodeSkipThreshold
);
_shaderProgram->setUniform(_uniformCache.fluxColorAlpha, _fluxColorAlpha);
_shaderProgram->setUniform(_uniformCache.earthPos, earthPos);
_shaderProgram->setUniform(_uniformCache.distanceThreshold, _distanceThreshold);
_shaderProgram->setUniform(_uniformCache.proximityNodesSize, _proximityNodesSize);
_shaderProgram->setUniform(
_uniformCache.time,
global::windowDelegate->applicationTime()
);
_shaderProgram->setUniform(
_uniformCache.maxNodeDistanceSize,
_maxNodeDistanceSize
);
_shaderProgram->setUniform(
_uniformCache.usingCameraPerspective,
_cameraPerspectiveEnabled
);
_shaderProgram->setUniform(_uniformCache.drawCircles, _drawingCircles);
_shaderProgram->setUniform(_uniformCache.drawHollow, _drawingHollow);
_shaderProgram->setUniform(_uniformCache.useGaussian, _gaussianAlphaFilter);
_shaderProgram->setUniform(
_uniformCache.perspectiveDistanceFactor,
_perspectiveDistanceFactor
);
_shaderProgram->setUniform(_uniformCache.minMaxNodeSize, _minMaxNodeSize);
_shaderProgram->setUniform(_uniformCache.usingPulse, _pulseEnabled);
_shaderProgram->setUniform(
_uniformCache.usingGaussianPulse,
_gaussianPulseEnabled
);
glm::vec3 cameraPos = data.camera.positionVec3() * data.modelTransform.rotation;
_shaderProgram->setUniform("cameraPos", cameraPos);
if (_colorMode == static_cast<int>(ColorMethod::ByFluxValue)) {
ghoul::opengl::TextureUnit textureUnit;
textureUnit.activate();
_transferFunction->bind(); // Calls update internally
_shaderProgram->setUniform("colorTable", textureUnit);
}
glBindVertexArray(_vertexArrayObject);
glDrawArrays(
GL_POINTS,
0,
static_cast<GLsizei>(_vertexPositions.size())
);
glBindVertexArray(0);
_shaderProgram->deactivate();
}
void RenderableFluxNodes::computeSequenceEndTime() {
if (_nStates > 1) {
const double lastTriggerTime = _startTimes[_nStates - 1];
const double sequenceDuration = lastTriggerTime - _startTimes[0];
const double averageStateDuration = sequenceDuration /
(static_cast<double>(_nStates) - 1.0);
_sequenceEndTime = lastTriggerTime + averageStateDuration;
}
else if (_nStates == 1) {
// If there's just one state it should never disappear!
_sequenceEndTime = std::numeric_limits<double>::max();
}
else {
LERROR("No states were found. The position file include this data");
}
}
void RenderableFluxNodes::update(const UpdateData& data) {
if (!_enabled) {
return;
}
if (_shaderProgram->isDirty()) {
_shaderProgram->rebuildFromFile();
}
bool needsUpdate = true;
//Everything below is for updating depending on time
const double currentTime = data.time.j2000Seconds();
const bool isInInterval = (currentTime >= _startTimes[0]) &&
(currentTime < _sequenceEndTime);
//const bool isInInterval = true;
if (isInInterval) {
const size_t nextIdx = _activeTriggerTimeIndex + 1;
if (
// true => We stepped back to a time represented by another state
currentTime < _startTimes[_activeTriggerTimeIndex] ||
// true => We stepped forward to a time represented by another state
(nextIdx < _nStates && currentTime >= _startTimes[nextIdx]))
{
updateActiveTriggerTimeIndex(currentTime);
} // else {we're still in same state as previous frame (no changes needed)}
}
else {
_activeTriggerTimeIndex = -1;
needsUpdate = false;
}
if (needsUpdate && !_statesPos[_activeTriggerTimeIndex].empty()) {
_vertexPositions = _statesPos[_activeTriggerTimeIndex];
_vertexColor = _statesColor[_activeTriggerTimeIndex];
_vertexRadius = _statesRadius[_activeTriggerTimeIndex];
needsUpdate = false;
updatePositionBuffer();
updateVertexColorBuffer();
updateVertexFilteringBuffer();
}
if (_shaderProgram->isDirty()) {
_shaderProgram->rebuildFromFile();
ghoul::opengl::updateUniformLocations(
*_shaderProgram,
_uniformCache,
UniformNames
);
}
}
void RenderableFluxNodes::updatePositionBuffer() {
glBindVertexArray(_vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);
glBufferData(
GL_ARRAY_BUFFER,
_vertexPositions.size() * sizeof(glm::vec3),
_vertexPositions.data(),
GL_STATIC_DRAW
);
glEnableVertexAttribArray(0);
glEnable(GL_PROGRAM_POINT_SIZE);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void RenderableFluxNodes::updateVertexColorBuffer() {
glBindVertexArray(_vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, _vertexColorBuffer);
glBufferData(
GL_ARRAY_BUFFER,
_vertexColor.size() * sizeof(float),
_vertexColor.data(),
GL_STATIC_DRAW
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void RenderableFluxNodes::updateVertexFilteringBuffer() {
glBindVertexArray(_vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, _vertexFilteringBuffer);
glBufferData(
GL_ARRAY_BUFFER,
_vertexRadius.size() * sizeof(float),
_vertexRadius.data(),
GL_STATIC_DRAW
);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
} // namespace openspace

View File

@@ -0,0 +1,214 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include <openspace/rendering/renderable.h>
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/properties/vector/vec2property.h>
#include <openspace/properties/vector/vec4property.h>
#include <openspace/rendering/transferfunction.h>
#include <ghoul/opengl/uniformcache.h>
#include <atomic>
namespace openspace {
class RenderableFluxNodes : public Renderable {
public:
RenderableFluxNodes(const ghoul::Dictionary& dictionary);
void initialize() override;
void initializeGL() override;
void deinitializeGL() override;
bool isReady() const override;
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
static documentation::Documentation Documentation();
private:
void definePropertyCallbackFunctions();
void populateStartTimes();
void computeSequenceEndTime();
void setupProperties();
void updateActiveTriggerTimeIndex(double currentTime);
void loadNodeData(int energybinOption);
void updatePositionBuffer();
void updateVertexColorBuffer();
void updateVertexFilteringBuffer();
std::vector<GLsizei> _lineCount;
std::vector<GLint> _lineStart;
// Used to determine if lines should be colored UNIFORMLY or by Flux Value
enum class ColorMethod {
ByFluxValue = 0,
Uniform = 1
};
enum class GoesEnergyBins {
Emin01 = 0,
Emin03 = 1
};
enum class ScalingMethod {
Flux = 0,
RFlux = 1,
R2Flux = 2,
Log10RFlux = 3,
LnRFlux = 4
};
enum class NodeSkipMethod {
Uniform = 0,
Flux = 1,
Radius = 2,
Streamnumber = 3
};
enum class EnhanceMethod {
SizeScaling = 0,
ColorTables = 1,
SizeAndColor = 2,
Illuminance = 3,
};
UniformCache(streamColor, nodeSize, proximityNodesSize,
thresholdFlux, colorMode, filterLower, filterUpper, scalingMode, colorTableRange,
domainLimZ, nodeSkip, nodeSkipDefault, nodeSkipEarth, nodeSkipMethod,
nodeSkipFluxThreshold, nodeSkipRadiusThreshold, fluxColorAlpha,
earthPos, distanceThreshold, time, maxNodeDistanceSize, usingCameraPerspective,
drawCircles, drawHollow, useGaussian, perspectiveDistanceFactor, minMaxNodeSize,
usingPulse, usingGaussianPulse)
_uniformCache;
std::filesystem::path _binarySourceFolderPath;
// Active index of _startTimes
int _activeTriggerTimeIndex = -1;
// Number of states in the sequence
uint32_t _nStates = 0;
// Estimated end of sequence.
double _sequenceEndTime;
// OpenGL Vertex Array Object
GLuint _vertexArrayObject = 0;
// OpenGL Vertex Buffer Object containing the vertex positions
GLuint _vertexPositionBuffer = 0;
// OpenGL Vertex Buffer Object containing the Flux values used for coloring
// the nodes
GLuint _vertexColorBuffer = 0;
// OpenGL Vertex Buffer Object containing the positions to filter the nodes
GLuint _vertexFilteringBuffer = 0;
// OpenGL Vertex Buffer Object containing the index of nodes
GLuint _vertexindexBuffer = 0;
std::unique_ptr<ghoul::opengl::ProgramObject> _shaderProgram;
// Transfer function used to color lines when _colorMethod is set to by_flux_value
std::unique_ptr<TransferFunction> _transferFunction;
std::vector<std::string> _binarySourceFiles;
// Contains the _triggerTimes for all streams in the sequence
std::vector<double> _startTimes;
// Contains vertexPositions
std::vector<glm::vec3> _vertexPositions;
// Contains vertex flux values for color
std::vector<float> _vertexColor;
// Contains radius of vertices
std::vector<float> _vertexRadius;
// Stores the states position
std::vector<std::vector<glm::vec3>> _statesPos;
// Stores the states color
std::vector<std::vector<float>> _statesColor;
// Stores the states radius
std::vector<std::vector<float>> _statesRadius;
// Group to hold properties regarding distance to earth
properties::PropertyOwner _earthdistGroup;
// Property to show different energybins
properties::OptionProperty _goesEnergyBins;
// Group to hold the color properties
properties::PropertyOwner _styleGroup;
// Uniform/transfer function
properties::OptionProperty _colorMode;
// Uniform stream Color
properties::Vec4Property _streamColor;
// Path to transferfunction
properties::StringProperty _colorTablePath;
// Valid range for the color table
properties::Vec2Property _colorTableRange;
// The value of alpha for the flux color mode
properties::FloatProperty _fluxColorAlpha;
// Group to hold the particle properties
properties::PropertyOwner _streamGroup;
// Scaling options
properties::OptionProperty _scalingMethod;
// Group for how many nodes to render dependent on radius and flux
properties::PropertyOwner _nodesAmountGroup;
// Size of simulated node particles
properties::FloatProperty _nodeSize;
// Threshold from earth to decide the distance for which the nodeSize gets larger
properties::FloatProperty _distanceThreshold;
// Change size of nodes close to earth
properties::FloatProperty _proximityNodesSize;
// Maximum size of nodes at a certin distance
properties::FloatProperty _maxNodeDistanceSize;
properties::Vec2Property _minMaxNodeSize;
// Valid range along the Z-axis
properties::Vec2Property _domainZ;
// Threshold flux value
properties::FloatProperty _thresholdFlux;
// Filtering nodes within a range
properties::FloatProperty _filteringLower;
// Filtering nodes with a upper range
properties::FloatProperty _filteringUpper;
// Amount of nodes to show
properties::IntProperty _amountofNodes;
// Nodeskipping options
properties::OptionProperty _nodeskipMethod;
// amount of nodes to show outside of filterrange
properties::IntProperty _defaultNodeSkip;
// The Flux threshold to decide the line between
//_pDefaultNodeSkip and _pAmountofNodes
properties::FloatProperty _fluxNodeskipThreshold;
//The nodeskip for values within the range of the radius threshold to Earth
properties::IntProperty _earthNodeSkip;
// The Radius threshold to decide the line between
//_pDefaultNodeSkip and _pAmountofNodes
properties::FloatProperty _radiusNodeSkipThreshold;
properties::PropertyOwner _cameraPerspectiveGroup;
properties::BoolProperty _cameraPerspectiveEnabled;
properties::BoolProperty _drawingCircles;
properties::BoolProperty _drawingHollow;
properties::BoolProperty _gaussianAlphaFilter;
properties::FloatProperty _perspectiveDistanceFactor;
properties::BoolProperty _pulseEnabled;
properties::BoolProperty _gaussianPulseEnabled;
};
} // namespace openspace

View File

@@ -0,0 +1,327 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include <modules/space/rendering/renderabletravelspeed.h>
#include <modules/base/basemodule.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/globals.h>
#include <openspace/query/query.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/distanceconstants.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/filesystem.h>
#include <optional>
namespace {
constexpr const char* _loggerCat = "renderableTravelSpeed";
constexpr const std::array<const char*, 2> UniformNames = {"lineColor", "opacity"};
constexpr openspace::properties::Property::PropertyInfo SpeedInfo = {
"TravelSpeed",
"Speed of travel",
"The speed of light is the default value."
};
constexpr openspace::properties::Property::PropertyInfo TargetInfo = {
"TargetNode",
"Target object",
"This value sets which scene graph node to target with the light speed indicator"
};
constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
"Color",
"Color",
"This value determines the RGB color for the line."
};
constexpr openspace::properties::Property::PropertyInfo LineOpacityInfo = {
"Opacity",
"Opacity",
"This value determines the opacity for the line."
};
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
"LineWidth",
"Line Width",
"This value specifies the line width."
};
constexpr openspace::properties::Property::PropertyInfo IndicatorLengthInfo = {
"IndicatorLength",
"Indicator Length",
"This value specifies the length of the light indicator set in light seconds."
};
constexpr openspace::properties::Property::PropertyInfo FadeLengthInfo = {
"FadeLength",
"Fade Length",
"This value specifies the length of the faded tail of the light indicator "
"set in light seconds."
};
struct [[codegen::Dictionary(RenderableLightTravel)]] Parameters {
// [[codegen::verbatim(TargetInfo.description)]]
std::string target;
// [[codegen::verbatim(SpeedInfo.description)]]
std::optional<double> travelSpeed;
// [[codegen::verbatim(LineColorInfo.description)]]
std::optional<glm::vec3> color;
// [[codegen::verbatim(LineOpacityInfo.description)]]
std::optional<float> opacity;
// [[codegen::verbatim(LineWidthInfo.description)]]
std::optional<float> lineWidth;
// [[codegen::verbatim(IndicatorLengthInfo.description)]]
std::optional<int> indicatorLength;
// [[codegen::verbatim(FadeLengthInfo.description)]]
std::optional<int> fadeLength;
};
#include "renderabletravelspeed_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation RenderableTravelSpeed::Documentation() {
return codegen::doc<Parameters>("base_renderable_renderabletravelspeed");
}
RenderableTravelSpeed::RenderableTravelSpeed(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _targetName(TargetInfo)
, _travelSpeed(
SpeedInfo,
distanceconstants::LightSecond,
1.0,
distanceconstants::LightSecond
)
, _indicatorLength(IndicatorLengthInfo, 1, 1, 360)
, _fadeLength(FadeLengthInfo, 1, 0, 360)
, _lineColor(LineColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
, _opacity(LineOpacityInfo, 1.f, 0.f, 1.f)
, _lineWidth(LineWidthInfo, 2.f, 1.f, 20.f)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
setRenderBin(RenderBin::Overlay);
_lineColor = p.color.value_or(_lineColor);
_lineColor.setViewOption(properties::Property::ViewOptions::Color);
addProperty(_lineColor);
_opacity = p.opacity.value_or(_opacity);
addProperty(_opacity);
_lineWidth = p.lineWidth.value_or(_lineWidth);
addProperty(_lineWidth);
_indicatorLength = p.indicatorLength.value_or(_indicatorLength);
addProperty(_indicatorLength);
_fadeLength = p.fadeLength.value_or(_fadeLength);
addProperty(_fadeLength);
_targetName = p.target;
addProperty(_targetName);
_targetName.onChange([this]() {
if (SceneGraphNode* n = sceneGraphNode(_targetName); n) {
_targetNode = n;
_targetPosition = _targetNode->worldPosition();
_lightTravelTime = calculateLightTravelTime(
_sourcePosition,
_targetPosition
);
calculateDirectionVector();
reinitiateTravel();
}
});
_travelSpeed = p.travelSpeed.value_or(_travelSpeed);
addProperty(_travelSpeed);
_travelSpeed.onChange([this]() {
reinitiateTravel();
});
}
void RenderableTravelSpeed::initialize() {
_targetNode = sceneGraphNode(_targetName);
if (_targetNode == nullptr) {
throw ghoul::RuntimeError("Could not find targetNode");
}
}
void RenderableTravelSpeed::initializeGL() {
_shaderProgram = BaseModule::ProgramObjectManager.request(
"Travelspeed",
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
return global::renderEngine->buildRenderProgram(
"Travelspeed",
absPath("${MODULE_SPACE}/shaders/travelspeed_vs.glsl"),
absPath("${MODULE_SPACE}/shaders/travelspeed_fs.glsl")
);
}
);
glGenVertexArrays(1, &_vaoId);
glGenBuffers(1, &_vBufferId);
ghoul::opengl::updateUniformLocations(*_shaderProgram, _uniformCache, UniformNames);
}
void RenderableTravelSpeed::deinitializeGL() {
BaseModule::ProgramObjectManager.release(
"Travelspeed",
[](ghoul::opengl::ProgramObject* p) {
global::renderEngine->removeRenderProgram(p);
}
);
glDeleteVertexArrays(1, &_vaoId);
glDeleteBuffers(1, &_vBufferId);
}
double RenderableTravelSpeed::calculateLightTravelTime(glm::dvec3 startPosition,
glm::dvec3 targetPosition) {
return glm::distance(targetPosition, startPosition) / _travelSpeed;
}
void RenderableTravelSpeed::calculateDirectionVector() {
_directionVector = glm::normalize(_targetPosition - _sourcePosition);
}
void RenderableTravelSpeed::calculateVerticesPositions() {
// 3: start of light, 2: start of fade, 1: end of fade
_vertexPositions.headOfLight = _travelSpeed * _timeSinceStart * _directionVector;
// This if statment is there to not start the line from behind the source node
if (_timeSinceStart < _indicatorLength) {
_vertexPositions.betweenLightAndFade = glm::vec3(0.0, 0.0, 0.0); // = source node
}
else {
_vertexPositions.betweenLightAndFade =
_travelSpeed * (_timeSinceStart - _indicatorLength) * _directionVector;
}
// This if statment is there to not start the line from behind the source node
if (_timeSinceStart < (_indicatorLength + _fadeLength)) {
_vertexPositions.endOfFade = glm::vec3(0.0, 0.0, 0.0); // = source node
}
else {
_vertexPositions.endOfFade = _travelSpeed *
(_timeSinceStart - _indicatorLength - _fadeLength) * _directionVector;
}
}
void RenderableTravelSpeed::updateVertexData() {
calculateVerticesPositions();
glBindVertexArray(_vaoId);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferId);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(VertexPositions),
&_vertexPositions,
GL_DYNAMIC_DRAW
);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glBindVertexArray(0);
}
void RenderableTravelSpeed::reinitiateTravel() {
_initiationTime = global::timeManager->time().j2000Seconds();
_arrivalTime = _initiationTime + _lightTravelTime;
}
bool RenderableTravelSpeed::isReady() const{
return _shaderProgram != nullptr;
}
void RenderableTravelSpeed::update(const UpdateData& data) {
if (_initiationTime == -1.0) {
_initiationTime = data.time.j2000Seconds();
_arrivalTime = _initiationTime + _lightTravelTime;
}
_targetPosition = _targetNode->worldPosition();
SceneGraphNode* mySGNPointer = _parent;
ghoul_assert(mySGNPointer, "Renderable have to be owned by scene graph node");
_sourcePosition = mySGNPointer->worldPosition();
_lightTravelTime = calculateLightTravelTime(
_sourcePosition,
_targetPosition
);
const double currentTime = data.time.j2000Seconds();
// Unless we've reached the target
if (_initiationTime < currentTime && _arrivalTime > currentTime) {
_timeSinceStart = currentTime - _initiationTime;
calculateDirectionVector();
updateVertexData();
}
else { // in case we've reached the target
reinitiateTravel();
}
_shaderProgram->setUniform("lineColor", _lineColor);
_shaderProgram->setUniform("opacity", _opacity);
}
void RenderableTravelSpeed::render(const RenderData& data, RendererTasks& ) {
if (!_enabled) {
return;
}
_shaderProgram->activate();
const glm::dmat4 modelTransform =
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) *
glm::dmat4(data.modelTransform.rotation) *
glm::scale(glm::dmat4(1.0), data.modelTransform.scale);
const glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() *
modelTransform;
_shaderProgram->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
_shaderProgram->setUniform("projectionTransform", data.camera.projectionMatrix());
#ifndef __APPLE__
glLineWidth(_lineWidth);
#else
glLineWidth(1.f);
#endif
glBindVertexArray(_vaoId);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferId);
glDrawArrays(GL_LINE_STRIP, 0, 3);
glBindVertexArray(0);
_shaderProgram->deactivate();
}
} // namespace openspace

View File

@@ -0,0 +1,95 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_SPACE___RENDERABLETRAVELSPEED___H__
#define __OPENSPACE_MODULE_SPACE___RENDERABLETRAVELSPEED___H__
#include <openspace/rendering/renderable.h>
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/vector/vec3property.h>
#include <ghoul/opengl/uniformcache.h>
namespace openspace {
class SceneGraphNode;
namespace documentation { struct Documentation; }
class RenderableTravelSpeed : public Renderable {
public:
RenderableTravelSpeed(const ghoul::Dictionary& dictionary);
static documentation::Documentation Documentation();
void initializeGL() override;
void initialize() override;
void deinitializeGL() override;
bool isReady() const override;
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
private:
double calculateLightTravelTime(glm::dvec3 startPosition, glm::dvec3 targetPosition);
void calculateVerticesPositions();
void calculateDirectionVector();
void updateVertexData();
void reinitiateTravel();
UniformCache(lineColor, opacity) _uniformCache;
properties::StringProperty _targetName;
SceneGraphNode* _targetNode = nullptr;
properties::DoubleProperty _travelSpeed;
properties::IntProperty _indicatorLength;
properties::IntProperty _fadeLength;
properties::FloatProperty _lineWidth;
properties::FloatProperty _opacity;
properties::Vec3Property _lineColor;
struct VertexPositions {
glm::vec3 endOfFade;
glm::vec3 betweenLightAndFade;
glm::vec3 headOfLight;
};
VertexPositions _vertexPositions;
glm::dvec3 _sourcePosition;
glm::dvec3 _targetPosition;
double _lightTravelTime;
glm::dvec3 _directionVector;
double _initiationTime = -1.0;
double _arrivalTime;
double _timeSinceStart = -1.0;
ghoul::opengl::ProgramObject* _shaderProgram = nullptr;
// The vertex attribute location for position
// must correlate to layout location in vertex shader
GLuint _vaoId = 0;
GLuint _vBufferId = 0;
};
} // namespace openspace
#endif //__OPENSPACE_MODULE_SPACE___RENDERABLETRAVELSPEED___H__

View File

@@ -0,0 +1,96 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include "fragment.glsl"
in vec2 vs_st;
in vec4 vs_color;
in float vs_depth;
in float vs_closeToEarth;
uniform bool drawCircles;
uniform bool drawHollow;
uniform bool useGaussian;
uniform bool usingCameraPerspective;
uniform bool usingGaussianPulse;
uniform vec3 cameraPos;
Fragment getFragment() {
vec4 fragColor = vs_color;
if (vs_color.a == 0) {
discard;
}
vec2 pos = vec2(0.5) - vs_st;
float r = length(pos) * 2.0;
float a = atan(pos.y, pos.x);
float f = cos(a * 3.0);
vec3 color = vec3(0.0);
color = vec3(1.0 - smoothstep(f, f, r));
Fragment frag;
frag.depth = vs_depth;
frag.color = fragColor;
vec2 coord = gl_PointCoord - vec2(0.5);
if (drawCircles && length(coord) > 0.5) {
discard;
}
if (drawHollow &&
length(coord) < 0.4 &&
(vs_closeToEarth > 0.5 || distance(cameraPos, vec3(0.0)) < 500000000000.0))
{
if (usingGaussianPulse &&
usingCameraPerspective &&
vs_closeToEarth > 0.5)
{
if (length(coord) < 0.3) {
float e = 2.718055;
float y = pow(e, - (pow(length(coord), 2.0)) /( 2.0 * pow(0.2, 2.0)));
if (y < 0.05) {
discard;
}
frag.color.a = y;
}
}
else {
discard;
}
}
if (useGaussian) {
float e = 2.718055;
float y = pow(e, - (pow(length(coord), 2.0)) /( 2.0 * pow(0.2, 2.0)));
if (y < 0.05) {
discard;
}
frag.color.a = y;
}
frag.gPosition = vec4(1e27, 1e27, 1e27, 1.0);
return frag;
}

View File

@@ -0,0 +1,245 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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"
// Inputs
// Should be provided in meters
layout(location = 0) in vec3 in_position;
// The extra value used to color lines
layout(location = 1) in float fluxValue;
// The extra value used to mask out parts of lines
layout(location = 2) in float rValue;
// These should correspond to the enum 'ColorMode'
const int colorByFluxValue = 0;
const int uniformColor = 1;
const int uniformskip = 0;
const int fluxSkip = 1;
const int radiusSkip = 2;
const int fluxMode = 0;
const int RFlux = 1;
const int R2Flux = 2;
const int log10RFlux = 3;
const int lnRFlux = 4;
const float AUtoMeter = 149597871000.0;
out vec4 vs_color;
out float vs_depth;
out vec2 vs_st;
out float vs_closeToEarth;
// General Uniforms that's always needed
uniform mat4 modelViewProjection;
// Uniforms needed to color by quantity
uniform int colorMode;
uniform sampler1D colorTable;
uniform vec2 colorTableRange;
uniform vec2 domainLimZ;
// Fluxnodes specific uniforms
uniform float nodeSize;
uniform vec4 streamColor;
uniform float thresholdFlux;
uniform float filterLower;
uniform float filterUpper;
uniform int scalingMode;
uniform int nodeSkipMethod;
uniform int nodeSkip;
uniform int nodeSkipDefault;
uniform int nodeSkipEarth;
uniform float nodeSkipFluxThreshold;
uniform float nodeSkipRadiusThreshold;
uniform float fluxColorAlpha;
uniform vec3 earthPos;
uniform float distanceThreshold;
uniform float proximityNodesSize;
uniform double time;
// Speicific uniforms for cameraperspective
uniform float maxNodeDistanceSize;
uniform vec3 cameraPos;
//uniform vec2 screenSize;
uniform bool usingCameraPerspective;
uniform float perspectiveDistanceFactor;
uniform vec2 minMaxNodeSize;
uniform bool usingPulse;
vec4 getTransferFunctionColor(sampler1D inColorTable) {
// Remap the color scalar to a [0,1] range
float scaleValue = 0.0;
if (scalingMode == fluxMode) {
scaleValue = fluxValue;
}
else if (scalingMode == RFlux) {
scaleValue = rValue * fluxValue;
}
else if (scalingMode == log10RFlux) {
//conversion from logbase e to log10 since glsl does not support log10.
float logtoTen = log(rValue) / log(10.0);
scaleValue = logtoTen * fluxValue;
}
else if (scalingMode == lnRFlux) {
scaleValue = log(rValue) * fluxValue;
}
else if (scalingMode == R2Flux) {
scaleValue = rValue * rValue * fluxValue;
}
float lookUpVal = (scaleValue - colorTableRange.x) /
(colorTableRange.y - colorTableRange.x);
return texture(inColorTable, lookUpVal);
}
bool checkIfSkipVertex() {
int nodeIndex = gl_VertexID;
if (nodeSkipMethod == uniformskip) {
if (mod(nodeIndex, nodeSkip) == 0) {
return true;
}
}
else if (nodeSkipMethod == fluxSkip) {
if (fluxValue > nodeSkipFluxThreshold && mod(nodeIndex, nodeSkip) == 0) {
return true;
}
if (fluxValue < nodeSkipFluxThreshold && mod(nodeIndex, nodeSkipDefault) == 0) {
return true;
}
}
else if (nodeSkipMethod == radiusSkip) {
if (rValue < nodeSkipRadiusThreshold && mod(nodeIndex, nodeSkip) == 0) {
return true;
}
if (rValue > nodeSkipRadiusThreshold && mod(nodeIndex, nodeSkipDefault) == 0) {
return true;
}
}
return false;
}
void setEarthProximitySettings() {
float distancevec = distance(earthPos, in_position.xyz);
vs_closeToEarth = 0.0;
if (distancevec < AUtoMeter * distanceThreshold) {
if (usingPulse) {
int speed = 2;
int modulusResult = int(speed * time) % 2;
if (fluxValue > thresholdFlux){
if (modulusResult == 1) {
vs_color.a = 0.01;
}
else {
vs_color.a = 1.0;
}
}
else {
vs_color.a = 0.0;
}
}
vs_closeToEarth = 1.0;
if (mod(gl_VertexID, nodeSkipEarth) == 0) {
gl_PointSize = proximityNodesSize;
}
else {
vs_color = vec4(0.0);
}
}
}
void main() {
// Default gl_PointSize if it is not set anywhere else.
gl_PointSize = 2;
// Checking if we should render the vertex dependent on the vertexindex,
// by using modulus.
if ((checkIfSkipVertex() ||
distance(earthPos, in_position) < (distanceThreshold * AUtoMeter)) &&
filterLower < rValue / AUtoMeter &&
filterUpper > rValue / AUtoMeter &&
in_position.z > (domainLimZ.x * AUtoMeter) &&
in_position.z < (domainLimZ.y * AUtoMeter))
{
vs_color = getTransferFunctionColor(colorTable);
if (colorMode == colorByFluxValue) {
if (fluxValue > thresholdFlux) {
vs_color = getTransferFunctionColor(colorTable);
vs_color.a = fluxColorAlpha;
gl_PointSize = nodeSize;
}
else {
vs_color.a = 0.0;
}
}
else if (colorMode == uniformColor){
vs_color = streamColor;
}
setEarthProximitySettings();
}
else {
vs_color = vec4(0.0);
}
if (usingCameraPerspective) {
float rtemp = min(rValue, 1.0);
float maxDistance = 100000000000.0 * perspectiveDistanceFactor;
float distanceVec = distance(cameraPos, in_position.xyz);
if (distanceVec < maxDistance) {
float distScale = 1.0 - smoothstep(0.0, maxDistance, distanceVec);
float factorS = pow(distScale, 9.0) * 500.0;
if (distance(earthPos, in_position.xyz) < (distanceThreshold * AUtoMeter)) {
gl_PointSize = proximityNodesSize;
}
else {
gl_PointSize = factorS * maxNodeDistanceSize;
}
}
if (gl_PointSize > minMaxNodeSize.y) {
gl_PointSize = minMaxNodeSize.y;
}
if (gl_PointSize < minMaxNodeSize.x) {
gl_PointSize = minMaxNodeSize.x;
}
}
vec4 position_in_meters = vec4(in_position, 1.0);
vec4 positionClipSpace = modelViewProjection * position_in_meters;
gl_Position = vec4(positionClipSpace.xy, 0.0, positionClipSpace.w);
vs_depth = gl_Position.w;
}

View File

@@ -0,0 +1,41 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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. *
****************************************************************************************/
#include "fragment.glsl"
#include "floatoperations.glsl"
in float vs_depth;
in vec4 finalColor;
in vec4 vs_positionViewSpace;
Fragment getFragment() {
Fragment frag;
frag.color = finalColor;
frag.depth = vs_depth;
frag.gPosition = vs_positionViewSpace;
frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0);
return frag;
}

View File

@@ -0,0 +1,61 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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(location = 0) in vec3 in_position;
out float vs_depth;
out vec4 vs_positionViewSpace;
out vec4 finalColor;
uniform vec3 lineColor;
uniform float opacity;
uniform mat4 modelViewTransform;
uniform mat4 projectionTransform;
void main() {
vs_positionViewSpace = vec4(modelViewTransform * dvec4(in_position, 1.0));
vec4 positionScreenSpace = projectionTransform * vs_positionViewSpace;
vs_depth = positionScreenSpace.w;
gl_Position = positionScreenSpace;
// Makes it liniarly fade betweet vertex 0 and 1
if (gl_VertexID == 0) {
finalColor = vec4(0.0, 0.0, 0.0, 0.0);
}
// Makes sure the line between index 1 and 2 is uniformly colored
else if (gl_VertexID == 1) {
finalColor = vec4(lineColor, opacity);
}
else if (gl_VertexID == 2) {
finalColor = vec4(lineColor, opacity);
}
// should never hit else
else {
finalColor = vec4(1.0, 1.0, 0.0, 1.0);
}
gl_Position.z = 0.f;
}

View File

@@ -25,11 +25,13 @@
#include <modules/space/spacemodule.h>
#include <modules/space/rendering/renderableconstellationbounds.h>
#include <modules/space/rendering/renderablefluxnodes.h>
#include <modules/space/rendering/renderablehabitablezone.h>
#include <modules/space/rendering/renderablerings.h>
#include <modules/space/rendering/renderablesatellites.h>
#include <modules/space/rendering/renderablesmallbody.h>
#include <modules/space/rendering/renderablestars.h>
#include <modules/space/rendering/renderabletravelspeed.h>
#include <modules/space/rendering/simplespheregeometry.h>
#include <modules/space/translation/keplertranslation.h>
#include <modules/space/translation/spicetranslation.h>
@@ -82,11 +84,13 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary& dictionary) {
fRenderable->registerClass<RenderableConstellationBounds>(
"RenderableConstellationBounds"
);
fRenderable->registerClass<RenderableFluxNodes>("RenderableFluxNodes");
fRenderable->registerClass<RenderableHabitableZone>("RenderableHabitableZone");
fRenderable->registerClass<RenderableRings>("RenderableRings");
fRenderable->registerClass<RenderableSatellites>("RenderableSatellites");
fRenderable->registerClass<RenderableSmallBody>("RenderableSmallBody");
fRenderable->registerClass<RenderableStars>("RenderableStars");
fRenderable->registerClass<RenderableTravelSpeed>("RenderableTravelSpeed");
auto fTranslation = FactoryManager::ref().factory<Translation>();
ghoul_assert(fTranslation, "Ephemeris factory was not created");
@@ -121,11 +125,13 @@ void SpaceModule::internalDeinitializeGL() {
std::vector<documentation::Documentation> SpaceModule::documentations() const {
return {
RenderableConstellationBounds::Documentation(),
RenderableFluxNodes::Documentation(),
RenderableHabitableZone::Documentation(),
RenderableRings::Documentation(),
RenderableSatellites::Documentation(),
RenderableSmallBody::Documentation(),
RenderableStars::Documentation(),
RenderableTravelSpeed::Documentation(),
SpiceRotation::Documentation(),
SpiceTranslation::Documentation(),
KeplerTranslation::Documentation(),

View File

@@ -69,6 +69,11 @@ void StateMachineModule::initializeStateMachine(const ghoul::Dictionary& states,
}
}
void StateMachineModule::deinitializeStateMachine() {
_machine.reset();
_machine = nullptr;
}
bool StateMachineModule::hasStateMachine() const {
return _machine != nullptr;
}
@@ -148,6 +153,13 @@ scripting::LuaLibrary StateMachineModule::luaLibrary() const {
"the identifier of the desired initial state. If left out, the first state "
"in the list will be used."
},
{
"destroyStateMachine",
&luascriptfunctions::destroyStateMachine,
{},
"",
"Destroys the current state machine and deletes all the memory."
},
{
"goToState",
&luascriptfunctions::goToState,

View File

@@ -43,6 +43,7 @@ public:
void initializeStateMachine(const ghoul::Dictionary& states,
const ghoul::Dictionary& transitions,
const std::optional<std::string> startState = std::nullopt);
void deinitializeStateMachine();
bool hasStateMachine() const;

View File

@@ -47,6 +47,15 @@ int createStateMachine(lua_State* L) {
return 0;
}
int destroyStateMachine(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::destroyStateMachine");
StateMachineModule* module = global::moduleEngine->module<StateMachineModule>();
module->deinitializeStateMachine();
return 0;
}
int goToState(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::goToState");
std::string newState = ghoul::lua::value<std::string>(L);

View File

@@ -59,7 +59,7 @@ namespace {
// settings, the file(s) pointed to by this URLSynchronization will always be
// downloaded, thus overwriting the local files. This is useful for files that are
// updated regularly remotely and should be fetch at every startup
std::optional<bool> forceOverride [[codegen::key("override")]];
std::optional<bool> forceOverride [[codegen::key("Override")]];
// If this value is set to 'true' (the default), the hash of the URL is appended
// to the directory name to produce a unique directory under all circumstances. If

View File

@@ -46,7 +46,7 @@ public:
void setDimensions(const glm::uvec3& dimensions);
//VoxelType get(const glm::ivec3& coordinates) const; // TODO: Implement this
//VoxelType get(const size_t index) const; // TODO: Implement this
std::unique_ptr<RawVolume<VoxelType>> read();
std::unique_ptr<RawVolume<VoxelType>> read(bool invertZ = false);
private:
size_t coordsToIndex(const glm::uvec3& cartesian) const;

View File

@@ -77,9 +77,8 @@ glm::uvec3 RawVolumeReader<VoxelType>::indexToCoords(size_t linear) const {
return indexToCoords(linear, dimensions());
}
template <typename VoxelType>
std::unique_ptr<RawVolume<VoxelType>> RawVolumeReader<VoxelType>::read() {
std::unique_ptr<RawVolume<VoxelType>> RawVolumeReader<VoxelType>::read(bool invertZ) {
glm::uvec3 dims = dimensions();
std::unique_ptr<RawVolume<VoxelType>> volume = std::make_unique<RawVolume<VoxelType>>(
dims
@@ -103,7 +102,24 @@ std::unique_ptr<RawVolume<VoxelType>> RawVolumeReader<VoxelType>::read() {
throw ghoul::RuntimeError("Error reading volume file");
}
return volume;
if (invertZ) {
std::unique_ptr<RawVolume<VoxelType>> newVolume =
std::make_unique<RawVolume<VoxelType>>(dims);
for (int i = 0; i < volume->nCells(); ++i) {
const glm::uvec3& coords = volume->indexToCoords(i);
glm::uvec3 newcoords = glm::uvec3(coords.x, coords.y, dims.z - coords.z - 1);
size_t newIndex = volume->coordsToIndex(newcoords);
size_t oldIndex = volume->coordsToIndex(coords);
newVolume->set(newcoords, volume->get(coords));
}
return newVolume;
}
else {
return volume;
}
}
} // namespace openspace::volume

View File

@@ -76,7 +76,7 @@ public:
void setVolumeTexture(std::shared_ptr<ghoul::opengl::Texture> texture);
std::shared_ptr<ghoul::opengl::Texture> volumeTexture() const;
void setTransferFunction(std::shared_ptr<TransferFunction> transferFunction);
void setTransferFunction(std::shared_ptr<openspace::TransferFunction> transferFunction);
void setStepSize(float stepSize);
float opacity() const;
@@ -94,7 +94,7 @@ private:
std::shared_ptr<VolumeClipPlanes> _clipPlanes;
std::shared_ptr<ghoul::opengl::Texture> _volumeTexture;
std::shared_ptr<TransferFunction> _transferFunction;
std::shared_ptr<openspace::TransferFunction> _transferFunction;
BoxGeometry _boundingBox;
VolumeGridType _gridType;
glm::mat4 _modelTransform = glm::mat4(1.f);

View File

@@ -50,94 +50,104 @@
namespace {
constexpr const char* _loggerCat = "RenderableTimeVaryingVolume";
const char* KeyStepSize = "StepSize";
const char* KeyGridType = "GridType";
const float SecondsInOneDay = 60 * 60 * 24;
constexpr const float VolumeMaxOpacity = 500;
static const openspace::properties::Property::PropertyInfo StepSizeInfo = {
"stepSize",
"StepSize",
"Step Size",
"" // @TODO Missing documentation
"Specifies how often to sample on the raycaster. Lower step -> higher resolution."
};
constexpr openspace::properties::Property::PropertyInfo GridTypeInfo = {
"gridType",
"GridType",
"Grid Type",
"", // @TODO Missing documentation
"Spherical or Cartesian grid.",
openspace::properties::Property::Visibility::Developer
};
constexpr openspace::properties::Property::PropertyInfo SecondsBeforeInfo = {
"secondsBefore",
"SecondsBefore",
"Seconds before",
"" // @TODO Missing documentation
"Specifies the number of seconds to show the first timestep before its "
"actual time. The default value is 0."
};
constexpr openspace::properties::Property::PropertyInfo SecondsAfterInfo = {
"secondsAfter",
"SecondsAfter",
"Seconds after",
"" // @TODO Missing documentation
"Specifies the number of seconds to show the the last timestep after its "
"actual time."
};
constexpr openspace::properties::Property::PropertyInfo SourceDirectoryInfo = {
"sourceDirectory",
"SourceDirectory",
"Source Directory",
"" // @TODO Missing documentation
"Specifies the path to load timesteps from."
};
constexpr openspace::properties::Property::PropertyInfo TransferFunctionInfo = {
"transferFunctionPath",
"TransferFunctionPath",
"Transfer Function Path",
""
"Specifies the transfer function file path."
};
constexpr openspace::properties::Property::PropertyInfo TriggerTimeJumpInfo = {
"triggerTimeJump",
"TriggerTimeJump",
"Jump",
"" // @TODO Missing documentation
"Sets the time to be the first time of the volume sequence."
};
constexpr openspace::properties::Property::PropertyInfo JumpToTimestepInfo = {
"jumpToTimestep",
"JumpToTimestep",
"Jump to timestep",
"" // @TODO Missing documentation
"Lets you scrub through the sequence's time steps."
};
constexpr openspace::properties::Property::PropertyInfo CurrentTimeStepInfo = {
"currentTimestep",
"Current timestep",
"" // @TODO Missing documentation
constexpr openspace::properties::Property::PropertyInfo OpacityInfo = {
"Opacity",
"Opacity",
"The volumes general opacity."
};
constexpr openspace::properties::Property::PropertyInfo rNormalizationInfo = {
"rNormalization",
"RNormalization",
"Radius normalization",
"" // @TODO Missing documentation
};
constexpr openspace::properties::Property::PropertyInfo rUpperBoundInfo = {
"rUpperBound",
"RUpperBound",
"Radius upper bound",
"" // @TODO Missing documentation
"Limit the volume's radius"
};
struct [[codegen::Dictionary(RenderableTimeVaryingVolume)]] Parameters {
// Specifies the path to load timesteps from
// [[codegen::verbatim(SourceDirectoryInfo.description)]]
std::string sourceDirectory;
// Specifies the transfer function file path
// [[codegen::verbatim(TransferFunctionInfo.description)]]
std::string transferFunction;
// Specifies the number of seconds to show the the first timestep before its
// actual time. The default value is 0
// [[codegen::verbatim(SecondsBeforeInfo.description)]]
std::optional<float> secondsBefore;
// Specifies the number of seconds to show the the last timestep after its
// actual time
// [[codegen::verbatim(SecondsAfterInfo.description)]]
float secondsAfter;
// Specifies if you want to invert the volume data at it z-axis.
std::optional<bool> invertDataAtZ;
// [[codegen::verbatim(OpacityInfo.description)]]
std::optional<float> opacity;
// [[codegen::verbatim(StepSizeInfo.description)]]
std::optional<double> stepSize;
// [[codegen::verbatim(GridTypeInfo.description)]]
std::optional<std::string> gridType;
// @TODO Missing documentation
std::optional<ghoul::Dictionary> clipPlanes;
};
#include "renderabletimevaryingvolume_codegen.cpp"
@@ -154,6 +164,7 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
: Renderable(dictionary)
, _gridType(GridTypeInfo, properties::OptionProperty::DisplayType::Dropdown)
, _stepSize(StepSizeInfo, 0.02f, 0.001f, 0.1f)
, _opacity(OpacityInfo, 10.f, 0.f, VolumeMaxOpacity)
, _rNormalization(rNormalizationInfo, 0.f, 0.f, 2.f)
, _rUpperBound(rUpperBoundInfo, 1.f, 0.f, 2.f)
, _secondsBefore(SecondsBeforeInfo, 0.f, 0.01f, SecondsInOneDay)
@@ -162,7 +173,7 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
, _transferFunctionPath(TransferFunctionInfo)
, _triggerTimeJump(TriggerTimeJumpInfo)
, _jumpToTimestep(JumpToTimestepInfo, 0, 0, 256)
, _currentTimestep(CurrentTimeStepInfo, 0, 0, 256)
, _invertDataAtZ(false)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -172,6 +183,8 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
_transferFunctionPath,
[](const openspace::TransferFunction&) {}
);
_invertDataAtZ = p.invertDataAtZ.value_or(_invertDataAtZ);
_gridType.addOptions({
{ static_cast<int>(volume::VolumeGridType::Cartesian), "Cartesian grid" },
@@ -179,8 +192,10 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
});
_gridType = static_cast<int>(volume::VolumeGridType::Cartesian);
if (dictionary.hasValue<double>(KeyStepSize)) {
_stepSize = static_cast<float>(dictionary.value<double>(KeyStepSize));
_stepSize = p.stepSize.value_or(_stepSize);
if (p.opacity.has_value()) {
_opacity = *p.opacity * VolumeMaxOpacity;
}
_secondsBefore = p.secondsBefore.value_or(_secondsBefore);
@@ -191,10 +206,8 @@ RenderableTimeVaryingVolume::RenderableTimeVaryingVolume(
_clipPlanes->setIdentifier("clipPlanes");
_clipPlanes->setGuiName("Clip Planes");
if (dictionary.hasValue<std::string>(KeyGridType)) {
VolumeGridType gridType = volume::parseGridType(
dictionary.value<std::string>(KeyGridType)
);
if (p.gridType.has_value()) {
VolumeGridType gridType = volume::parseGridType(*p.gridType);
_gridType = static_cast<std::underlying_type_t<VolumeGridType>>(gridType);
}
@@ -225,7 +238,7 @@ void RenderableTimeVaryingVolume::initializeGL() {
"{}/{}.rawvolume", _sourceDirectory.value(), t.baseName
);
RawVolumeReader<float> reader(path, t.metadata.dimensions);
t.rawVolume = reader.read();
t.rawVolume = reader.read(_invertDataAtZ);
float min = t.metadata.minValue;
float diff = t.metadata.maxValue - t.metadata.minValue;
@@ -238,7 +251,6 @@ void RenderableTimeVaryingVolume::initializeGL() {
for (size_t i = 0; i < t.rawVolume->nCells(); ++i) {
t.histogram->add(data[i]);
}
// TODO: handle normalization properly for different timesteps + transfer function
t.texture = std::make_shared<ghoul::opengl::Texture>(
@@ -276,14 +288,13 @@ void RenderableTimeVaryingVolume::initializeGL() {
}
});
_triggerTimeJump.onChange([this] () { jumpToTimestep(_jumpToTimestep); });
_triggerTimeJump.onChange([this]() { jumpToTimestep(_jumpToTimestep); });
_jumpToTimestep.onChange([this] () { jumpToTimestep(_jumpToTimestep); });
_jumpToTimestep.onChange([this]() { jumpToTimestep(_jumpToTimestep); });
const int lastTimestep = !_volumeTimesteps.empty() ?
static_cast<int>(_volumeTimesteps.size() - 1) :
0;
_currentTimestep.setMaxValue(lastTimestep);
_jumpToTimestep.setMaxValue(lastTimestep);
addProperty(_stepSize);
@@ -293,7 +304,6 @@ void RenderableTimeVaryingVolume::initializeGL() {
addProperty(_triggerTimeJump);
addProperty(_jumpToTimestep);
addProperty(_currentTimestep);
addProperty(_rNormalization);
addProperty(_rUpperBound);
addProperty(_gridType);
@@ -317,7 +327,12 @@ void RenderableTimeVaryingVolume::loadTimestepMetadata(const std::string& path)
try {
ghoul::Dictionary dictionary = ghoul::lua::loadDictionaryFromFile(path);
metadata = RawVolumeMetadata::createFromDictionary(dictionary);
} catch (...) {
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
return;
}
catch (...) {
return;
}
@@ -404,7 +419,6 @@ void RenderableTimeVaryingVolume::update(const UpdateData&) {
if (_raycaster) {
Timestep* t = currentTimestep();
_currentTimestep = timestepIndex(t);
// Set scale and translation matrices:
// The original data cube is a unit cube centered in 0
@@ -437,7 +451,7 @@ void RenderableTimeVaryingVolume::update(const UpdateData&) {
_raycaster->setVolumeTexture(nullptr);
}
_raycaster->setStepSize(_stepSize);
_raycaster->setOpacity(_opacity * VolumeMaxOpacity);
_raycaster->setOpacity(_opacity);
_raycaster->setRNormalization(_rNormalization);
_raycaster->setRUpperBound(_rUpperBound);
}

View File

@@ -33,15 +33,16 @@
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/rendering/transferfunction.h>
namespace openspace {
class Histogram;
struct RenderData;
class TransferFunction;
} // namespace openspace
namespace openspace::volume {
//class TransferFunction;
class BasicVolumeRaycaster;
template <typename T> class RawVolume;
class VolumeClipPlanes;
@@ -81,6 +82,7 @@ private:
std::shared_ptr<VolumeClipPlanes> _clipPlanes;
properties::FloatProperty _stepSize;
properties::FloatProperty _opacity;
properties::FloatProperty _rNormalization;
properties::FloatProperty _rUpperBound;
properties::FloatProperty _secondsBefore;
@@ -90,10 +92,10 @@ private:
properties::TriggerProperty _triggerTimeJump;
properties::IntProperty _jumpToTimestep;
properties::IntProperty _currentTimestep;
std::map<double, Timestep> _volumeTimesteps;
std::unique_ptr<BasicVolumeRaycaster> _raycaster;
bool _invertDataAtZ;
std::shared_ptr<openspace::TransferFunction> _transferFunction;
};

View File

@@ -134,7 +134,7 @@ void create() {
ghoul_assert(eventEngine, "No eventEngine");
currentPos += sizeof(EventEngine);
#else // ^^^ WIN32 / !WIN32 vvv
downloadManager = new EventEngine;
eventEngine = new EventEngine;
#endif // WIN32
#ifdef WIN32