mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-21 12:29:04 -06:00
Merge branch 'master' into feature/animation-fixes
This commit is contained in:
@@ -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
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
33
data/assets/scene/solarsystem/planets/earth/kernels/GSM.ti
Normal file
33
data/assets/scene/solarsystem/planets/earth/kernels/GSM.ti
Normal 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
|
||||
@@ -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
|
||||
@@ -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"}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
57
data/assets/scene/solarsystem/sun/EUV_layer.asset
Normal file
57
data/assets/scene/solarsystem/sun/EUV_layer.asset
Normal 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"}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
41
data/assets/scene/solarsystem/sun/kernels/HEEQ180.tf
Normal file
41
data/assets/scene/solarsystem/sun/kernels/HEEQ180.tf
Normal 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'
|
||||
@@ -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",
|
||||
|
||||
@@ -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"}
|
||||
}
|
||||
8
data/assets/util/streamnodes_textures.asset
Normal file
8
data/assets/util/streamnodes_textures.asset
Normal file
@@ -0,0 +1,8 @@
|
||||
local TexturesPath = asset.syncedResource({
|
||||
Type = "HttpSynchronization",
|
||||
Name = "Streamnodes textures",
|
||||
Identifier = "streamnodes_textures",
|
||||
Version = 4
|
||||
})
|
||||
|
||||
asset.export("TexturesPath", TexturesPath)
|
||||
209
data/profiles/bastille-day.profile
Normal file
209
data/profiles/bastille-day.profile
Normal 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
|
||||
}
|
||||
}
|
||||
Submodule ext/ghoul updated: 874300a089...af5545a13d
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -75,6 +75,7 @@ private:
|
||||
void createPlane();
|
||||
|
||||
properties::BoolProperty _billboard;
|
||||
properties::BoolProperty _mirrorBackside;
|
||||
properties::FloatProperty _size;
|
||||
properties::Vec3Property _multiplyColor;
|
||||
|
||||
|
||||
321
modules/base/rendering/renderableplanetimevaryingimage.cpp
Normal file
321
modules/base/rendering/renderableplanetimevaryingimage.cpp
Normal 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
|
||||
77
modules/base/rendering/renderableplanetimevaryingimage.h
Normal file
77
modules/base/rendering/renderableplanetimevaryingimage.h
Normal 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__
|
||||
553
modules/base/rendering/renderabletimevaryingsphere.cpp
Normal file
553
modules/base/rendering/renderabletimevaryingsphere.cpp
Normal 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
|
||||
105
modules/base/rendering/renderabletimevaryingsphere.h
Normal file
105
modules/base/rendering/renderabletimevaryingsphere.h
Normal 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__
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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})
|
||||
|
||||
|
||||
856
modules/space/rendering/renderablefluxnodes.cpp
Normal file
856
modules/space/rendering/renderablefluxnodes.cpp
Normal 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
|
||||
214
modules/space/rendering/renderablefluxnodes.h
Normal file
214
modules/space/rendering/renderablefluxnodes.h
Normal 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
|
||||
327
modules/space/rendering/renderabletravelspeed.cpp
Normal file
327
modules/space/rendering/renderabletravelspeed.cpp
Normal 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
|
||||
95
modules/space/rendering/renderabletravelspeed.h
Normal file
95
modules/space/rendering/renderabletravelspeed.h
Normal 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__
|
||||
96
modules/space/shaders/fluxnodes_fs.glsl
Normal file
96
modules/space/shaders/fluxnodes_fs.glsl
Normal 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;
|
||||
}
|
||||
245
modules/space/shaders/fluxnodes_vs.glsl
Normal file
245
modules/space/shaders/fluxnodes_vs.glsl
Normal 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;
|
||||
}
|
||||
41
modules/space/shaders/travelspeed_fs.glsl
Normal file
41
modules/space/shaders/travelspeed_fs.glsl
Normal 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;
|
||||
}
|
||||
61
modules/space/shaders/travelspeed_vs.glsl
Normal file
61
modules/space/shaders/travelspeed_vs.glsl
Normal 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;
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user