diff --git a/data/assets/scene/digitaluniverse/hdf.asset b/data/assets/scene/digitaluniverse/hdf.asset
new file mode 100644
index 0000000000..51e30e3dfd
--- /dev/null
+++ b/data/assets/scene/digitaluniverse/hdf.asset
@@ -0,0 +1,84 @@
+local assetHelper = asset.require('util/asset_helper')
+local circle = asset.require('util/circle').circle
+
+local HUDFSpeck = asset.syncedResource({
+ Name = "HUDF Speck",
+ Type = "HttpSynchronization",
+ Identifier = "digitaluniverse_hudf_speck",
+ Version = 1
+})
+
+local ColorMap = asset.syncedResource({
+ Name = "HUDF color map",
+ Type = "HttpSynchronization",
+ Identifier = "digitaluniverse_hudf_textures",
+ Version = 1
+})
+
+local object = {
+ Identifier = "HubbleDeepField",
+ Renderable = {
+ Type = "RenderableBillboardsCloud",
+ Enabled = false,
+ Color = { 1.0, 1.0, 1.0 },
+ Opacity = 1.0,
+ File = HUDFSpeck .. "/hudf.speck",
+ Texture = circle .. "/circle.png",
+ ColorMap = ColorMap .. "/hudf.cmap",
+ ColorOption = { "redshift", "proximity" },
+ ColorRange = { { 0.0, 0.075 }, { 1.0, 25.0 } },
+ Unit = "Mpc",
+ ScaleFactor = 520.0,
+ BillboardMaxSize = 4.7,
+ EnablePixelSizeControl = true
+ },
+ GUI = {
+ Name = "Hubble Deep Field",
+ Path = "/Universe/Galaxies",
+ Description = [[
+ Hubble Ultra Deep Field galaxy survey
+ Data Reference: Hubble Ultra Deep Field 2012 program (Ellis+, Koekemoer+, 2013)
+ ]],
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, { object })
+
+asset.meta = {
+ Name = "Hubble Ultra Deep Field",
+ Version = "1.1",
+ Description = "Hubble Ultra Deep Field galaxy survey",
+ Author = "Frank Summers (STScI), Brian Abbott (AMNH)",
+ Identifiers = {"HubbleDeepField"},
+ URL = "http://www.haydenplanetarium.org/universe",
+ License = [[
+ Copyright (c) American Museum of Natural History. All rights reserved.
+
+ Downloading the Atlas:
+ AMNH offers the Atlas free of charge via our website, http://www.haydenplanetarium.org/.
+ The User is free to download and/or duplicate verbatim copies of the Atlas provided this
+ license and copyright information accompany the Atlas.
+
+ Modifying the Atlas:
+ The user is free to modify the Atlas by either adding data or altering existing data,
+ provided it is for personal use only. Once the user modifies the Atlas, it is no longer
+ part of AMNH's Atlas and cannot be used publicly alongside or within the Atlas without
+ written permission from AMNH.
+
+ Distributing the Atlas:
+ The user is forbidden to distribute and use the Atlas for profit, as part of a software
+ and/or production system that will subsequently be redistributed, or for public consumption
+ (via print, electronic media, or broadcast/produced pieces) without written permission
+ from AMNH.
+
+ Neither the names of American Museum of Natural History and Hayden Planetarium nor the names
+ of their contributors may be used to endorse or promote products derived from this Atlas
+ without specific, prior written permission.
+
+ The Atlas is free but is offered WITHOUT ANY WARRANTY of any kind. We provide the Atlas as
+ is and take no responsibility for any damage resulting from the use of this Atlas. The entire
+ risk as to the quality and performance of this product is with the user.
+
+ For more information, please visit http://www.haydenplanetarium.org/universe
+ ]]
+}
diff --git a/data/assets/scene/solarsystem/missions/jwst/HUDFImage.asset b/data/assets/scene/solarsystem/missions/jwst/HUDFImage.asset
new file mode 100644
index 0000000000..7f45814a94
--- /dev/null
+++ b/data/assets/scene/solarsystem/missions/jwst/HUDFImage.asset
@@ -0,0 +1,77 @@
+local assetHelper = asset.require('util/asset_helper')
+local transforms = asset.require('scene/solarsystem/planets/earth/transforms')
+local jwstTransforms = asset.require('scene/solarsystem/missions/jwst/jwst')
+local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
+
+local image = asset.syncedResource({
+ Name = "HUDF image",
+ Type = "HttpSynchronization",
+ Identifier = "hudf_image",
+ Version = 1
+})
+
+local DISTANCE = 9.2E15;
+
+-- ra = 3h32m38.92s
+-- dec = -27d47m29.37s
+-- distance = 9.2E15 m (set to size of view sphere)
+local HUDFPosition = {
+ Identifier = "HUDFPosition",
+ Parent = transforms.EarthInertial.Identifier,
+ Transform = {
+ Translation = {
+ Type = "StaticTranslation",
+ Position = {
+ 0.53039024 * DISTANCE,
+ 0.70802069 * DISTANCE,
+ -0.46625412 * DISTANCE
+ }
+ }
+ },
+ GUI = {
+ Name = "Hubble Ultra Deep field",
+ Path = "/Solar System/Missions/JWST",
+ Hidden = true
+ }
+}
+
+local HUDFImage = {
+ Identifier = "HUDFImage",
+ Enabled = false,
+ Type = "ScreenSpaceImageLocal",
+ Name = "Hubble Ultra Deep field",
+ UseRadiusAzimuthElevation = true,
+ FaceCamera = false,
+ RadiusAzimuthElevation = { 200.0, 0.5, 0.15 },
+ UsePerspectiveProjection = false,
+ Opacity = 1.0,
+ TexturePath = image .. "/Hubble_ultra_deep_field.jpg",
+ Tag = { "mission_jwst_hudf" },
+}
+
+local HUDFJWSTLine = {
+ Identifier = "HUDFJWSTLine",
+ Parent = sunTransforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableNodeLine",
+ StartNode = HUDFPosition.Identifier,
+ EndNode = jwstTransforms.JWSTPosition.Identifier,
+ Color = { 0.5, 0.5, 0.5 },
+ LineWidth = 2
+ },
+ Tag = { "mission_jwst_hudf" },
+ GUI = {
+ Name = "JWST to HUDF Line",
+ Path = "/Solar System/Missions/JWST",
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, { HUDFPosition, HUDFImage, HUDFJWSTLine })
+
+asset.onInitialize(function()
+ openspace.addScreenSpaceRenderable(HUDFImage)
+end)
+asset.onDeinitialize(function()
+ openspace.removeScreenSpaceRenderable(HUDFImage.Identifier)
+end)
diff --git a/data/assets/scene/solarsystem/missions/jwst/jwst.asset b/data/assets/scene/solarsystem/missions/jwst/jwst.asset
new file mode 100644
index 0000000000..7c4f338e32
--- /dev/null
+++ b/data/assets/scene/solarsystem/missions/jwst/jwst.asset
@@ -0,0 +1,304 @@
+local assetHelper = asset.require('util/asset_helper')
+local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
+
+asset.require('spice/base')
+asset.require('scene/solarsystem/planets/earth/lagrange_points/lagrange_points')
+local transforms = asset.require('scene/solarsystem/planets/earth/lagrange_points/L2')
+
+local JWSTKernel = asset.syncedResource({
+ Name = "JWST Kernel",
+ Type = "HttpSynchronization",
+ Identifier = "jwst_kernels",
+ Version = 1
+})
+
+local JWSTHorizons = asset.syncedResource({
+ Name = "JWST Horizons",
+ Type = "HttpSynchronization",
+ Identifier = "jwst_horizons",
+ Version = 1
+})
+
+local model = asset.syncedResource({
+ Name = "JWST Model",
+ Type = "HttpSynchronization",
+ Identifier = "jwst_model",
+ Version = 1
+})
+
+local band = asset.syncedResource({
+ Name = "JWST band texture",
+ Type = "HttpSynchronization",
+ Identifier = "jwst_band_texture",
+ Version = 1
+})
+
+local JWSTPosition = {
+ Identifier = "JWSTPosition",
+ Parent = transforms.L2.Identifier,
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "JWST",
+ Observer = "392", -- L2
+ Kernels = JWSTKernel .. "/jwst_horizons_20200101_20240101_v01.bsp"
+ },
+ },
+ GUI = {
+ Name = "JWST Position",
+ Path = "/Solar System/Missions/JWST",
+ Hidden = true,
+ }
+}
+
+local JWSTRotation = {
+ Identifier = "JWSTRotation",
+ Parent = JWSTPosition.Identifier,
+ Transform = {
+ Rotation = {
+ Type = "FixedRotation",
+ Attached = "JWSTRotation",
+ XAxis = { 1, 0, 0 },
+ XAxisOrthogonal = true,
+ YAxisInvert = true,
+ YAxis = sunTransforms.SolarSystemBarycenter.Identifier
+ }
+ },
+ GUI = {
+ Name = "JWST Rotation",
+ Path = "/Solar System/Missions/JWST",
+ Hidden = true,
+ }
+}
+
+local JWSTBand = {
+ Identifier = "JWSTBand",
+ Parent = JWSTPosition.Identifier,
+ Transform = {
+ Rotation = {
+ Type = "FixedRotation",
+ Attached = "JWSTBand",
+ XAxis = { 1, 0, 0 },
+ XAxisOrthogonal = true,
+ ZAxis = sunTransforms.SolarSystemBarycenter.Identifier
+ }
+ },
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableSphere",
+ Texture = band .. "/JWST-band.png",
+ Size = 9.2E15,
+ Segments = 50,
+ DisableFadeInOut = true,
+ Orientation = "Inside",
+ Opacity = 0.05,
+ UseAdditiveBlending = true,
+ },
+ Tag = { "mission_jwst_fov" },
+ GUI = {
+ Name = "JWST View Band",
+ Path = "/Solar System/Missions/JWST"
+ }
+}
+
+local JWSTModel = {
+ Identifier = "JWSTModel",
+ Parent = JWSTRotation.Identifier,
+ TimeFrame = {
+ Type = "TimeFrameInterval",
+ Start = "2020 JAN 01",
+ End = "2024 JAN 01"
+ },
+ Renderable = {
+ Type = "RenderableModel",
+ GeometryFile = model .. "/JWSTFBX.osmodel",
+ ModelScale = "Foot",
+ InvertModelScale = true,
+ EnableAnimation = true,
+ --TODO: Update theese when the new animation is finished
+ AnimationStartTime = "2018 10 01 15:00:00",
+ AnimationMode = "Once",
+ LightSources = {
+ {
+ Type = "SceneGraphLightSource",
+ Identifier = "Sun",
+ Node = sunTransforms.SolarSystemBarycenter.Identifier,
+ Intensity = 1.0
+ }
+ },
+ PerformShading = true,
+ DisableFaceCulling = true
+ },
+ GUI = {
+ Name = "James Webb Space Telescope",
+ Path = "/Solar System/Missions/JWST",
+ }
+}
+
+local JWSTTrail = {
+ Identifier = "JWSTTrail",
+ Parent = transforms.L2.Identifier,
+ Renderable = {
+ Type = "RenderableTrailOrbit",
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "JWST",
+ Observer = "392", -- L2
+ Kernels = JWSTKernel .. "/jwst_horizons_20200101_20240101_v01.bsp"
+ },
+ Color = { 0.9, 0.9, 0.0 },
+ Period = 91.3105,
+ Resolution = 100
+ },
+ GUI = {
+ Name = "JWST Trail",
+ Path = "/Solar System/Missions/JWST"
+ }
+}
+
+local JWSTSunTrail = {
+ Identifier = "JWSTSunTrail",
+ Parent = sunTransforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableTrailOrbit",
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "JWST",
+ Observer = "SUN",
+ Kernels = JWSTKernel .. "/jwst_horizons_20200101_20240101_v01.bsp"
+ },
+ Color = { 0.0, 0.9, 0.9 },
+ Period = 365.242,
+ Resolution = 1000
+ },
+ GUI = {
+ Name = "JWST Sun Trail",
+ Path = "/Solar System/Missions/JWST"
+ }
+}
+
+local JWSTFov = {
+ Identifier = "JWSTFov",
+ Parent = JWSTModel.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderablePrism",
+ Segments = 6,
+ Lines = 3,
+ Radius = 3.25,
+ LineWidth = 1.0,
+ Color = { 1.0, 1.0, 1.0 },
+ Length = 9.2E15
+ },
+ Transform = {
+ Rotation = {
+ Type = "StaticRotation",
+ Rotation = { 0, 0, math.rad(30) }
+ },
+ },
+ Tag = { "mission_jwst_fov" },
+ GUI = {
+ Name = "JWST Field of View",
+ Path = "/Solar System/Missions/JWST",
+ }
+}
+
+-- Launch
+local JWSTLaunchPosition = {
+ Identifier = "JWSTLaunchPosition",
+ Parent = transforms.L2.Identifier,
+ Transform = {
+ Translation = {
+ Type = "HorizonsTranslation",
+ HorizonsTextFile = JWSTHorizons .. "/horizons_jwst_launch.dat",
+ },
+ },
+ GUI = {
+ Name = "JWST Launch Position",
+ Path = "/Solar System/Missions/JWST",
+ Hidden = true,
+ }
+}
+
+local JWSTLaunchModel = {
+ Identifier = "JWSTLaunchModel",
+ Parent = JWSTLaunchPosition.Identifier,
+ TimeFrame = {
+ Type = "TimeFrameInterval",
+ Start = "2018 OCT 01 13:18:00",
+ End = "2019 OCT 01"
+ },
+ Transform = {
+ Rotation = {
+ Type = "FixedRotation",
+ Attached = "JWSTRotation",
+ XAxis = { 1, 0, 0 },
+ XAxisOrthogonal = true,
+ YAxisInvert = true,
+ YAxis = sunTransforms.SolarSystemBarycenter.Identifier
+ }
+ },
+ Renderable = {
+ Type = "RenderableModel",
+ GeometryFile = model .. "/JWSTFBX.osmodel",
+ ModelScale = "Foot",
+ InvertModelScale = true,
+ EnableAnimation = true,
+ --TODO: Update theese when the new animation is finished
+ AnimationStartTime = "2018 10 01 15:00:00",
+ AnimationMode = "Once",
+ LightSources = {
+ {
+ Type = "SceneGraphLightSource",
+ Identifier = "Sun",
+ Node = sunTransforms.SolarSystemBarycenter.Identifier,
+ Intensity = 1.0
+ }
+ },
+ PerformShading = true,
+ DisableFaceCulling = true
+ },
+ GUI = {
+ Name = "JWST Launch Model",
+ Path = "/Solar System/Missions/JWST",
+ }
+}
+
+local JWSTLaunchTrail = {
+ Identifier = "JWSTLaunchTrail",
+ Parent = transforms.L2.Identifier,
+ TimeFrame = {
+ Type = "TimeFrameInterval",
+ Start = "2018 OCT 01 13:18:00",
+ End = "2019 OCT 01"
+ },
+ Renderable = {
+ Type = "RenderableTrailTrajectory",
+ Translation = {
+ Type = "HorizonsTranslation",
+ HorizonsTextFile = JWSTHorizons .. "/horizons_jwst_launch.dat",
+ },
+ Color = { 0.9, 0.9, 0.0 },
+ StartTime = "2018 OCT 01 13:18:00",
+ EndTime = "2019 OCT 01",
+ SampleInterval = 600
+ },
+ GUI = {
+ Name = "JWST Launch Trail",
+ Path = "/Solar System/Missions/JWST"
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, {
+ JWSTTrail,
+ JWSTSunTrail,
+ JWSTLaunchTrail,
+ JWSTPosition,
+ JWSTLaunchPosition,
+ JWSTRotation,
+ JWSTBand,
+ JWSTModel,
+ JWSTLaunchModel,
+ JWSTFov
+})
diff --git a/data/assets/scene/solarsystem/planets/earth/lagrange_points/L1.asset b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L1.asset
new file mode 100644
index 0000000000..420ff19185
--- /dev/null
+++ b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L1.asset
@@ -0,0 +1,59 @@
+local assetHelper = asset.require('util/asset_helper')
+local transforms = asset.require('scene/solarsystem/sun/transforms')
+local circle = asset.require('util/circle').circle
+local kernels = asset.require('scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels').kernels
+asset.require('spice/base')
+
+local L1 = {
+ Identifier = "L1",
+ Parent = transforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderablePlaneImageLocal",
+ RenderableType = "Opaque",
+ Billboard = true,
+ Size = 700E5,
+ Texture = circle .. "/circle.png",
+ BlendMode = "Additive"
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "391", -- L1
+ Observer = "SUN",
+ Kernels = kernels .. "/L1_de431.bsp"
+ }
+ },
+ Tag = { "lagrange_points_earth" , "lagrange_points_earth_l1" },
+ GUI = {
+ Name = "L1",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ }
+}
+
+local L1Label = {
+ Identifier = "L1Label",
+ Parent = L1.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableLabels",
+ Text = "L1",
+ FontSize = 20,
+ Size = 7.5,
+ MinMaxSize = { 1.0, 100.0},
+ OrientationOption = "Camera View Direction",
+ BlendMode = "Normal",
+ EnableFading = false
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l1" },
+ GUI = {
+ Name = "L1 Label",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ Description = "Main label for L1"
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, {
+ L1,
+ L1Label
+})
diff --git a/data/assets/scene/solarsystem/planets/earth/lagrange_points/L2.asset b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L2.asset
new file mode 100644
index 0000000000..0f84519837
--- /dev/null
+++ b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L2.asset
@@ -0,0 +1,127 @@
+local assetHelper = asset.require('util/asset_helper')
+local transforms = asset.require('scene/solarsystem/sun/transforms')
+local circle = asset.require('util/circle').circle
+local kernels = asset.require('scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels').kernels
+asset.require('spice/base')
+
+local L2Small = {
+ Identifier = "L2Small",
+ Parent = transforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Type = "RenderablePlaneImageLocal",
+ RenderableType = "Opaque",
+ Billboard = true,
+ Size = 400E4,
+ Texture = circle .. "/circle.png",
+ BlendMode = "Additive"
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "392", -- L2
+ Observer = "SUN",
+ Kernels = kernels .. "/L2_de431.bsp"
+ }
+ },
+ Tag = { "lagrange_points_earth_l2_small" },
+ GUI = {
+ Name = "Small L2",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ }
+}
+
+local L2 = {
+ Identifier = "L2",
+ Parent = transforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderablePlaneImageLocal",
+ RenderableType = "Opaque",
+ Billboard = true,
+ Size = 700E5,
+ Texture = circle .. "/circle.png",
+ BlendMode = "Additive"
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "392", -- L2
+ Observer = "SUN",
+ Kernels = kernels .. "/L2_de431.bsp"
+ }
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l2" },
+ GUI = {
+ Name = "L2",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ }
+}
+
+local L2SmallLabel = {
+ Identifier = "L2SmallLabel",
+ Parent = L2.Identifier,
+ Renderable = {
+ Enabled = true,
+ Type = "RenderableLabels",
+ Text = "L2",
+ FontSize = 20.0,
+ Size = 6.0,
+ MinMaxSize = { 1.0, 100.0 },
+ OrientationOption = "Camera View Direction",
+ BlendMode = "Normal",
+ EnableFading = false
+ },
+ Tag = { "lagrange_points_earth_l2_small" },
+ GUI = {
+ Name = "Small L2 Label",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ Description = "Small label for L2"
+ }
+}
+
+local L2Label = {
+ Identifier = "L2Label",
+ Parent = L2.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableLabels",
+ Text = "L2",
+ FontSize = 20,
+ Size = 7.5,
+ MinMaxSize = { 1.0, 100.0},
+ OrientationOption = "Camera View Direction",
+ BlendMode = "Normal",
+ EnableFading = false
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l2" },
+ GUI = {
+ Name = "L2 Label",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ Description = "Main label for L2"
+ }
+}
+
+local L2SunLine = {
+ Identifier = "L2SunLine",
+ Parent = transforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Type = "RenderableNodeLine",
+ StartNode = "Sun",
+ EndNode = "L2Small",
+ Color = { 0.5, 0.5, 0.5 },
+ LineWidth = 2
+ },
+ Tag = { "lagrange_points_earth_l2_small" },
+ GUI = {
+ Name = "Sun to L2 Line",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, {
+ L2Small,
+ L2,
+ L2SunLine,
+ L2SmallLabel,
+ L2Label
+})
diff --git a/data/assets/scene/solarsystem/planets/earth/lagrange_points/L4.asset b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L4.asset
new file mode 100644
index 0000000000..05ca2a57b5
--- /dev/null
+++ b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L4.asset
@@ -0,0 +1,59 @@
+local assetHelper = asset.require('util/asset_helper')
+local transforms = asset.require('scene/solarsystem/sun/transforms')
+local circle = asset.require('util/circle').circle
+local kernels = asset.require('scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels').kernels
+asset.require('spice/base')
+
+local L4 = {
+ Identifier = "L4",
+ Parent = transforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderablePlaneImageLocal",
+ RenderableType = "Opaque",
+ Billboard = true,
+ Size = 800E6,
+ Texture = circle .. "/circle.png",
+ BlendMode = "Additive"
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "394", -- L4
+ Observer = "SUN",
+ Kernels = kernels .. "/L4_de431.bsp"
+ }
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l4" },
+ GUI = {
+ Name = "L4",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ }
+}
+
+local L4Label = {
+ Identifier = "L4Label",
+ Parent = L4.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableLabels",
+ Text = "L4",
+ FontSize = 20,
+ Size = 8.5,
+ MinMaxSize = { 1.0, 100.0 },
+ OrientationOption = "Camera View Direction",
+ BlendMode = "Normal",
+ EnableFading = false
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l4" },
+ GUI = {
+ Name = "L4 Label",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ Description = "Main label for L4"
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, {
+ L4,
+ L4Label
+})
diff --git a/data/assets/scene/solarsystem/planets/earth/lagrange_points/L5.asset b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L5.asset
new file mode 100644
index 0000000000..dcaabb12b7
--- /dev/null
+++ b/data/assets/scene/solarsystem/planets/earth/lagrange_points/L5.asset
@@ -0,0 +1,59 @@
+local assetHelper = asset.require('util/asset_helper')
+local transforms = asset.require('scene/solarsystem/sun/transforms')
+local circle = asset.require('util/circle').circle
+local kernels = asset.require('scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels').kernels
+asset.require('spice/base')
+
+local L5 = {
+ Identifier = "L5",
+ Parent = transforms.SolarSystemBarycenter.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderablePlaneImageLocal",
+ RenderableType = "Opaque",
+ Billboard = true,
+ Size = 800E6,
+ Texture = circle .. "/circle.png",
+ BlendMode = "Additive"
+ },
+ Transform = {
+ Translation = {
+ Type = "SpiceTranslation",
+ Target = "395", -- L5
+ Observer = "SUN",
+ Kernels = kernels .. "/L5_de431.bsp"
+ }
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l5" },
+ GUI = {
+ Name = "L5",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ }
+}
+
+local L5Label = {
+ Identifier = "L5Label",
+ Parent = L5.Identifier,
+ Renderable = {
+ Enabled = false,
+ Type = "RenderableLabels",
+ Text = "L5",
+ FontSize = 20,
+ Size = 8.5,
+ MinMaxSize = { 1.0, 100.0 },
+ OrientationOption = "Camera View Direction",
+ BlendMode = "Normal",
+ EnableFading = false
+ },
+ Tag = { "lagrange_points_earth", "lagrange_points_earth_l5" },
+ GUI = {
+ Name = "L5 Label",
+ Path = "/Solar System/Planets/Earth/Lagrange points",
+ Description = "Main label for L5"
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, {
+ L5,
+ L5Label
+})
diff --git a/data/assets/scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels.asset b/data/assets/scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels.asset
new file mode 100644
index 0000000000..b78370a3a8
--- /dev/null
+++ b/data/assets/scene/solarsystem/planets/earth/lagrange_points/lagrange_kernels.asset
@@ -0,0 +1,8 @@
+local kernels = asset.syncedResource({
+ Name = "Lagrange Kernels",
+ Type = "HttpSynchronization",
+ Identifier = "earth_lagrange_kernels",
+ Version = 1
+})
+
+asset.export('kernels', kernels)
diff --git a/data/assets/scene/solarsystem/planets/earth/lagrange_points/lagrange_points.asset b/data/assets/scene/solarsystem/planets/earth/lagrange_points/lagrange_points.asset
new file mode 100644
index 0000000000..8c4d507ca0
--- /dev/null
+++ b/data/assets/scene/solarsystem/planets/earth/lagrange_points/lagrange_points.asset
@@ -0,0 +1,4 @@
+asset.require('scene/solarsystem/planets/earth/lagrange_points/L1')
+asset.require('scene/solarsystem/planets/earth/lagrange_points/L2')
+asset.require('scene/solarsystem/planets/earth/lagrange_points/L4')
+asset.require('scene/solarsystem/planets/earth/lagrange_points/L5')
diff --git a/data/assets/util/circle.asset b/data/assets/util/circle.asset
new file mode 100644
index 0000000000..4717b87883
--- /dev/null
+++ b/data/assets/util/circle.asset
@@ -0,0 +1,8 @@
+local circle = asset.syncedResource({
+ Name = "Circle",
+ Type = "HttpSynchronization",
+ Identifier = "circle_image",
+ Version = 1
+})
+
+asset.export('circle', circle)
diff --git a/data/profiles/jwst.profile b/data/profiles/jwst.profile
new file mode 100644
index 0000000000..d273706c84
--- /dev/null
+++ b/data/profiles/jwst.profile
@@ -0,0 +1,112 @@
+{
+ "assets": [
+ "base",
+ "scene/solarsystem/planets/earth/earth",
+ "scene/solarsystem/planets/earth/satellites/satellites",
+ "scene/solarsystem/missions/jwst/jwst",
+ "scene/solarsystem/missions/jwst/HUDFImage",
+ "scene/digitaluniverse/hdf"
+ ],
+ "camera": {
+ "altitude": 17000000.0,
+ "anchor": "Earth",
+ "latitude": 3.5559,
+ "longitude": -53.0515,
+ "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": [
+ {
+ "documentation": "Toggle trails on or off for satellites around Earth",
+ "gui_path": "/Earth",
+ "is_local": false,
+ "key": "S",
+ "name": "Toggle satellite trails",
+ "script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
+ },
+ {
+ "documentation": "Toggle points and labels for the Lagrangian points for Earth Sun system",
+ "gui_path": "/JWST",
+ "is_local": false,
+ "key": "P",
+ "name": "Toggle Lagrangian points",
+ "script": "local list = openspace.getProperty('{lagrange_points_earth}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
+ },
+ {
+ "documentation": "Toggle Hubble Ultra Deep Field image and line towards its coordinate",
+ "gui_path": "/JWST",
+ "is_local": false,
+ "key": "U",
+ "name": "Toggle Hubble Ultra Deep Field",
+ "script": "local list = openspace.getProperty('{mission_jwst_hudf}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
+ },
+ {
+ "documentation": "Toggle L2 label, point and line",
+ "gui_path": "/JWST",
+ "is_local": false,
+ "key": "O",
+ "name": "Toggle L2",
+ "script": "local list = openspace.getProperty('{lagrange_points_earth_l2_small}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
+ },
+ {
+ "documentation": "Toggle James Webb Space Telecope field of view and view band",
+ "gui_path": "/JWST",
+ "is_local": false,
+ "key": "V",
+ "name": "Toggle JWST field of view and view band",
+ "script": "local list = openspace.getProperty('{mission_jwst_fov}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
+ }
+ ],
+ "mark_nodes": [
+ "JWSTModel",
+ "JWSTTrail",
+ "L2",
+ "Earth",
+ "Moon",
+ "Sun"
+ ],
+ "meta": {
+ "author": "OpenSpace Team",
+ "description": "James Webb Space Telescope Profile. Adds the James Webb Space Telescope model with an estimated trajectery.",
+ "license": "MIT License",
+ "name": "James Webb Space Telescope",
+ "url": "https://www.openspaceproject.com",
+ "version": "1.0"
+ },
+ "properties": [
+ {
+ "name": "{earth_satellites}.Renderable.Enabled",
+ "type": "setPropertyValue",
+ "value": "false"
+ }
+ ],
+ "time": {
+ "type": "absolute",
+ "value": "2021-10-31T00:00:00"
+ },
+ "version": {
+ "major": 1,
+ "minor": 0
+ }
+}
diff --git a/ext/ghoul b/ext/ghoul
index 99a5599cc4..fcb8e8b964 160000
--- a/ext/ghoul
+++ b/ext/ghoul
@@ -1 +1 @@
-Subproject commit 99a5599cc4ce355b76bdc70dea1d69be8252ffb1
+Subproject commit fcb8e8b964c9c176733f4fdc22d117cac8d3f8b2
diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt
index 75e8508b89..4a69424b32 100644
--- a/modules/base/CMakeLists.txt
+++ b/modules/base/CMakeLists.txt
@@ -50,6 +50,7 @@ set(HEADER_FILES
rendering/renderableplane.h
rendering/renderableplaneimagelocal.h
rendering/renderableplaneimageonline.h
+ rendering/renderableprism.h
rendering/renderablesphere.h
rendering/renderabletrail.h
rendering/renderabletrailorbit.h
@@ -101,6 +102,7 @@ set(SOURCE_FILES
rendering/renderableplane.cpp
rendering/renderableplaneimagelocal.cpp
rendering/renderableplaneimageonline.cpp
+ rendering/renderableprism.cpp
rendering/renderablesphere.cpp
rendering/renderabletrail.cpp
rendering/renderabletrailorbit.cpp
@@ -141,6 +143,8 @@ set(SHADER_FILES
shaders/model_vs.glsl
shaders/plane_fs.glsl
shaders/plane_vs.glsl
+ shaders/prism_fs.glsl
+ shaders/prism_vs.glsl
shaders/renderabletrail_fs.glsl
shaders/renderabletrail_vs.glsl
shaders/screenspace_fs.glsl
diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp
index 883e73cc21..67f2332629 100644
--- a/modules/base/basemodule.cpp
+++ b/modules/base/basemodule.cpp
@@ -51,6 +51,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -131,6 +132,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) {
fRenderable->registerClass("RenderableNodeLine");
fRenderable->registerClass("RenderablePlaneImageLocal");
fRenderable->registerClass("RenderablePlaneImageOnline");
+ fRenderable->registerClass("RenderablePrism");
fRenderable->registerClass("RenderableRadialGrid");
fRenderable->registerClass("RenderableSphere");
fRenderable->registerClass("RenderableSphericalGrid");
diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp
index 67db6e27ec..892c7d6bd1 100644
--- a/modules/base/rendering/renderablemodel.cpp
+++ b/modules/base/rendering/renderablemodel.cpp
@@ -157,13 +157,27 @@ namespace {
Centimeter,
Decimeter,
Meter,
- Kilometer
+ Kilometer,
+
+ // Weird units
+ Thou,
+ Inch,
+ Foot,
+ Yard,
+ Chain,
+ Furlong,
+ Mile
};
// The scale of the model. For example if the model is in centimeters
// then ModelScale = Centimeter or ModelScale = 0.01
std::optional> modelScale;
+ // By default the given ModelScale is used to scale the model down,
+ // by setting this setting to true the model is instead scaled up with the
+ // given ModelScale
+ std::optional invertModelScale;
+
// Set if invisible parts (parts with no textures or materials) of the model
// should be forced to render or not.
std::optional forceRenderInvisible;
@@ -290,6 +304,8 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
ghoul::io::ModelReader::NotifyInvisibleDropped(_notifyInvisibleDropped)
);
+ _invertModelScale = p.invertModelScale.value_or(_invertModelScale);
+
if (p.modelScale.has_value()) {
if (std::holds_alternative(*p.modelScale)) {
Parameters::ScaleUnit scaleUnit =
@@ -318,10 +334,33 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
case Parameters::ScaleUnit::Kilometer:
distanceUnit = DistanceUnit::Kilometer;
break;
+
+ // Weired units
+ case Parameters::ScaleUnit::Thou:
+ distanceUnit = DistanceUnit::Thou;
+ break;
+ case Parameters::ScaleUnit::Inch:
+ distanceUnit = DistanceUnit::Inch;
+ break;
+ case Parameters::ScaleUnit::Foot:
+ distanceUnit = DistanceUnit::Foot;
+ break;
+ case Parameters::ScaleUnit::Yard:
+ distanceUnit = DistanceUnit::Yard;
+ break;
+ case Parameters::ScaleUnit::Chain:
+ distanceUnit = DistanceUnit::Chain;
+ break;
+ case Parameters::ScaleUnit::Furlong:
+ distanceUnit = DistanceUnit::Furlong;
+ break;
+ case Parameters::ScaleUnit::Mile:
+ distanceUnit = DistanceUnit::Mile;
+ break;
default:
throw ghoul::MissingCaseException();
}
- _modelScale = convertUnit(distanceUnit, DistanceUnit::Meter);
+ _modelScale = toMeter(distanceUnit);
}
else if (std::holds_alternative(*p.modelScale)) {
_modelScale = std::get(*p.modelScale);
@@ -329,6 +368,10 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
else {
throw ghoul::MissingCaseException();
}
+
+ if (_invertModelScale) {
+ _modelScale = 1.0 / _modelScale;
+ }
}
if (p.animationStartTime.has_value()) {
diff --git a/modules/base/rendering/renderablemodel.h b/modules/base/rendering/renderablemodel.h
index 39b9d3200d..1de33afe5b 100644
--- a/modules/base/rendering/renderablemodel.h
+++ b/modules/base/rendering/renderablemodel.h
@@ -81,6 +81,7 @@ private:
std::unique_ptr _geometry;
double _modelScale = 1.0;
+ bool _invertModelScale = false;
bool _forceRenderInvisible = false;
bool _notifyInvisibleDropped = true;
std::string _animationStart;
diff --git a/modules/base/rendering/renderableprism.cpp b/modules/base/rendering/renderableprism.cpp
new file mode 100644
index 0000000000..a5c9e3702a
--- /dev/null
+++ b/modules/base/rendering/renderableprism.cpp
@@ -0,0 +1,344 @@
+/*****************************************************************************************
+ * *
+ * 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
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+ constexpr const char _loggerCat[] = "RenderablePrism";
+
+ constexpr const std::array UniformNames = {
+ "modelViewProjectionTransform", "vs_color"
+ };
+
+ constexpr openspace::properties::Property::PropertyInfo SegmentsInfo = {
+ "Segments",
+ "Segments",
+ "The number of segments the shape of the prism should have."
+ };
+
+ constexpr openspace::properties::Property::PropertyInfo LinesInfo = {
+ "NumLines",
+ "Number of Lines",
+ "The number of lines connecting the two shapes of the prism."
+ };
+
+ static const openspace::properties::Property::PropertyInfo RadiusInfo = {
+ "Radius",
+ "Radius",
+ "The radius of the prism's shape in meters."
+ };
+
+ constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
+ "LineWidth",
+ "Line Width",
+ "This value specifies the line width."
+ };
+
+ constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
+ "Color",
+ "Color",
+ "This value determines the RGB color for the line."
+ };
+
+ constexpr openspace::properties::Property::PropertyInfo LengthInfo = {
+ "Length",
+ "Length",
+ "The length of the prism in meters."
+ };
+
+ // Generate vertices around the unit circle on the XY-plane
+ std::vector unitCircleVertices(int sectorCount) {
+ std::vector vertices;
+ vertices.reserve(2 * sectorCount);
+ float sectorStep = glm::two_pi() / sectorCount;
+
+ for (int i = 0; i < sectorCount; ++i) {
+ float sectorAngle = i * sectorStep;
+ vertices.push_back(cos(sectorAngle)); // x
+ vertices.push_back(sin(sectorAngle)); // y
+ }
+ return vertices;
+ }
+
+ struct [[codegen::Dictionary(RenderablePrism)]] Parameters {
+ // [[codegen::verbatim(SegmentsInfo.description)]]
+ int segments;
+
+ // [[codegen::verbatim(LinesInfo.description)]]
+ std::optional lines;
+
+ // [[codegen::verbatim(RadiusInfo.description)]]
+ std::optional radius;
+
+ // [[codegen::verbatim(LineWidthInfo.description)]]
+ std::optional lineWidth;
+
+ // [[codegen::verbatim(LineColorInfo.description)]]
+ std::optional color [[codegen::color()]];
+
+ // [[codegen::verbatim(LengthInfo.description)]]
+ std::optional length;
+ };
+#include "renderableprism_codegen.cpp"
+} // namespace
+
+namespace openspace {
+
+documentation::Documentation RenderablePrism::Documentation() {
+ documentation::Documentation doc = codegen::doc("base_renderable_prism");
+ return doc;
+}
+
+RenderablePrism::RenderablePrism(const ghoul::Dictionary& dictionary)
+ : Renderable(dictionary)
+ , _nShapeSegments(SegmentsInfo, 6, 3, 32)
+ , _nLines(LinesInfo, 6, 0, 32)
+ , _radius(RadiusInfo, 10.f, 0.f, 3.0e12f)
+ , _lineWidth(LineWidthInfo, 1.f, 1.f, 20.f)
+ , _lineColor(LineColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
+ , _length(LengthInfo, 20.f, 1.f, 3.0e12f)
+{
+ const Parameters p = codegen::bake(dictionary);
+
+ _nShapeSegments.onChange([&]() { _prismIsDirty = true; });
+ _nShapeSegments = p.segments;
+ addProperty(_nShapeSegments);
+
+ _nLines.onChange([&]() { _prismIsDirty = true; });
+ _nLines = p.lines.value_or(_nShapeSegments);
+ addProperty(_nLines);
+
+ _radius.setExponent(10.f);
+ _radius.onChange([&]() { _prismIsDirty = true; });
+ _radius = p.radius.value_or(_radius);
+ addProperty(_radius);
+
+ _lineWidth = p.lineWidth.value_or(_lineWidth);
+ addProperty(_lineWidth);
+
+ _lineColor.setViewOption(properties::Property::ViewOptions::Color);
+ _lineColor = p.color.value_or(_lineColor);
+ addProperty(_lineColor);
+
+ _length.setExponent(12.f);
+ _length.onChange([&]() { _prismIsDirty = true; });
+ _length = p.length.value_or(_length);
+ addProperty(_length);
+
+ addProperty(_opacity);
+}
+
+bool RenderablePrism::isReady() const {
+ return _shader != nullptr;
+}
+
+void RenderablePrism::initialize() {
+ updateVertexData();
+}
+
+void RenderablePrism::initializeGL() {
+ _shader = global::renderEngine->buildRenderProgram(
+ "PrismProgram",
+ absPath("${MODULE_BASE}/shaders/prism_vs.glsl"),
+ absPath("${MODULE_BASE}/shaders/prism_fs.glsl")
+ );
+ ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
+
+ glGenVertexArrays(1, &_vaoId);
+ glGenBuffers(1, &_vboId);
+ glGenBuffers(1, &_iboId);
+
+ glBindVertexArray(_vaoId);
+
+ updateBufferData();
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
+ glBindVertexArray(0);
+}
+
+void RenderablePrism::deinitializeGL() {
+ global::renderEngine->removeRenderProgram(_shader.get());
+ _shader = nullptr;
+
+ glDeleteVertexArrays(1, &_vaoId);
+ _vaoId = 0;
+
+ glDeleteBuffers(1, &_vboId);
+ _vboId = 0;
+
+ glDeleteBuffers(1, &_iboId);
+ _iboId = 0;
+}
+
+void RenderablePrism::updateVertexData() {
+ _vertexArray.clear();
+ _indexArray.clear();
+
+ // Get unit circle vertices on the XY-plane
+ std::vector unitVertices = unitCircleVertices(_nShapeSegments);
+ std::vector unitVerticesLines = unitCircleVertices(_nLines);
+
+ // Put base and top shape vertices into array
+ for (int i = 0; i < 2; ++i) {
+ float h = i * _length; // z value, 0 to _length
+
+ for (int j = 0, k = 0; j < _nShapeSegments && k < unitVertices.size(); ++j, k += 2) {
+ float ux = unitVertices[k];
+ float uy = unitVertices[k + 1];
+
+ _vertexArray.push_back(ux * _radius); // x
+ _vertexArray.push_back(uy * _radius); // y
+ _vertexArray.push_back(h); // z
+ }
+ }
+
+ // Put the vertices for the connecting lines into array
+ if (_nLines == 1) {
+ // In the case of just one line then connect the center points instead
+ // Center for base shape
+ _vertexArray.push_back(0.f);
+ _vertexArray.push_back(0.f);
+ _vertexArray.push_back(0.f);
+
+ // Center for top shape
+ _vertexArray.push_back(0.f);
+ _vertexArray.push_back(0.f);
+ _vertexArray.push_back(_length);
+ }
+ else {
+ for (int j = 0, k = 0; j < _nLines && k < unitVerticesLines.size(); ++j, k += 2) {
+ float ux = unitVerticesLines[k];
+ float uy = unitVerticesLines[k + 1];
+
+ // Base
+ _vertexArray.push_back(ux * _radius); // x
+ _vertexArray.push_back(uy * _radius); // y
+ _vertexArray.push_back(0.f); // z
+
+ // Top
+ _vertexArray.push_back(ux * _radius); // x
+ _vertexArray.push_back(uy * _radius); // y
+ _vertexArray.push_back(_length); // z
+ }
+ }
+
+ // Indices for Base shape
+ ghoul_assert(_nShapeSegments.value <= std::numeric_limit::max(), "Too many shape segments")
+ for (uint8_t i = 0; i < _nShapeSegments; ++i) {
+ _indexArray.push_back(i);
+ }
+
+ // Reset
+ _indexArray.push_back(255);
+
+ // Indices for Top shape
+ for (uint8_t i = _nShapeSegments; i < 2 * _nShapeSegments; ++i) {
+ _indexArray.push_back(i);
+ }
+
+ // Indices for connecting lines
+ for (int i = 0, k = 0; i < _nLines; ++i, k += 2) {
+ // Reset
+ _indexArray.push_back(255);
+
+ _indexArray.push_back(2 * _nShapeSegments + k);
+ _indexArray.push_back(2 * _nShapeSegments + k + 1);
+ }
+}
+
+void RenderablePrism::updateBufferData() {
+ glBindBuffer(GL_ARRAY_BUFFER, _vboId);
+ glBufferData(
+ GL_ARRAY_BUFFER,
+ _vertexArray.size() * sizeof(float),
+ _vertexArray.data(),
+ GL_STREAM_DRAW
+ );
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iboId);
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER,
+ _indexArray.size() * sizeof(uint8_t),
+ _indexArray.data(),
+ GL_STREAM_DRAW
+ );
+}
+
+void RenderablePrism::render(const RenderData& data, RendererTasks&) {
+ _shader->activate();
+
+ // Model transform and view transform needs to be in double precision
+ 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::mat4 modelViewProjectionTransform =
+ data.camera.projectionMatrix() *
+ glm::mat4(data.camera.combinedViewMatrix() * modelTransform);
+
+ // Uniforms
+ _shader->setUniform(_uniformCache.modelViewProjection, modelViewProjectionTransform);
+ _shader->setUniform(_uniformCache.color, glm::vec4(_lineColor.value(), _opacity));
+
+ // Render
+ glEnable(GL_PRIMITIVE_RESTART);
+ glPrimitiveRestartIndex(255);
+ glLineWidth(_lineWidth);
+ glBindVertexArray(_vaoId);
+
+ glDrawElements(GL_LINE_LOOP, static_cast(_indexArray.size()), GL_UNSIGNED_BYTE, nullptr);
+
+ glBindVertexArray(0);
+ global::renderEngine->openglStateCache().resetLineState();
+ glDisable(GL_PRIMITIVE_RESTART);
+
+ _shader->deactivate();
+}
+
+void RenderablePrism::update(const UpdateData&) {
+ if (_shader->isDirty()) {
+ _shader->rebuildFromFile();
+ ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames);
+ }
+ if (_prismIsDirty) {
+ updateVertexData();
+ updateBufferData();
+ _prismIsDirty = false;
+ }
+}
+
+} // namespace openspace
diff --git a/modules/base/rendering/renderableprism.h b/modules/base/rendering/renderableprism.h
new file mode 100644
index 0000000000..3acfb6953f
--- /dev/null
+++ b/modules/base/rendering/renderableprism.h
@@ -0,0 +1,83 @@
+/*****************************************************************************************
+ * *
+ * 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___RENDERABLEPRISM___H__
+#define __OPENSPACE_MODULE_BASE___RENDERABLEPRISM___H__
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ghoul::opengl { class ProgramObject; }
+
+namespace openspace {
+
+namespace documentation { struct Documentation; }
+
+class RenderablePrism : public Renderable {
+public:
+ RenderablePrism(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 updateVertexData();
+ void updateBufferData();
+
+ // Properties
+ properties::IntProperty _nShapeSegments;
+ properties::IntProperty _nLines;
+ properties::FloatProperty _radius;
+ properties::FloatProperty _lineWidth;
+ properties::Vec3Property _lineColor;
+ properties::FloatProperty _length;
+ UniformCache(modelViewProjection, color) _uniformCache;
+
+ std::unique_ptr _shader;
+ GLuint _vaoId = 0;
+ GLuint _vboId = 0;
+ GLuint _iboId = 0;
+ std::vector _vertexArray;
+ std::vector _indexArray;
+
+ bool _prismIsDirty = false;
+};
+
+} // namespace openspace
+
+#endif // __OPENSPACE_MODULE_BASE___RENDERABLEPRISM___H__
diff --git a/modules/base/shaders/prism_fs.glsl b/modules/base/shaders/prism_fs.glsl
new file mode 100644
index 0000000000..e659f56f6a
--- /dev/null
+++ b/modules/base/shaders/prism_fs.glsl
@@ -0,0 +1,36 @@
+/*****************************************************************************************
+ * *
+ * 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 float vs_depth;
+
+uniform vec4 vs_color;
+
+Fragment getFragment() {
+ Fragment frag;
+ frag.color = vs_color;
+ frag.depth = vs_depth;
+ return frag;
+}
diff --git a/modules/base/shaders/prism_vs.glsl b/modules/base/shaders/prism_vs.glsl
new file mode 100644
index 0000000000..bb8d4f68b0
--- /dev/null
+++ b/modules/base/shaders/prism_vs.glsl
@@ -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. *
+ ****************************************************************************************/
+
+#version __CONTEXT__
+
+#include "PowerScaling/powerScaling_vs.hglsl"
+
+layout (location = 0) in vec3 in_position;
+
+out float vs_depth;
+
+uniform mat4 modelViewProjectionTransform;
+
+void main() {
+ vec4 position = vec4(in_position, 1.0);
+ vec4 positionClipSpace = modelViewProjectionTransform * position;
+ vec4 positionScreenSpace = z_normalization(positionClipSpace);
+ gl_Position = positionScreenSpace;
+ vs_depth = positionScreenSpace.w;
+}
diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp
index aa54f729da..7e1010aad5 100644
--- a/src/rendering/renderengine.cpp
+++ b/src/rendering/renderengine.cpp
@@ -55,6 +55,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -480,6 +481,10 @@ void RenderEngine::initialize() {
std::make_unique()
);
+ ghoul::io::ModelReader::ref().addReader(
+ std::make_unique()
+ );
+
_versionString = OPENSPACE_VERSION_STRING_FULL;
if (global::versionChecker->hasLatestVersionInfo()) {
VersionChecker::SemanticVersion latest = global::versionChecker->latestVersion();
diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp
index 74c6204dd3..d39208d1a1 100644
--- a/src/scene/scene.cpp
+++ b/src/scene/scene.cpp
@@ -717,6 +717,20 @@ scripting::LuaLibrary Scene::luaLibrary() {
"Adds an interesting time to the current scene. The first argument is "
"the name of the time and the second argument is the time itself in the "
"format YYYY-MM-DDThh:mm:ss.uuu"
+ },
+ {
+ "worldPosition",
+ &luascriptfunctions::worldPosition,
+ {},
+ "string",
+ "Returns the world position of the scene graph node with the given string as identifier"
+ },
+ {
+ "worldRotation",
+ & luascriptfunctions::worldRotation,
+ {},
+ "string",
+ "Returns the world rotation matrix of the scene graph node with the given string as identifier"
}
}
};
diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl
index 6092fba38c..cb1d33fd52 100644
--- a/src/scene/scene_lua.inl
+++ b/src/scene/scene_lua.inl
@@ -908,4 +908,44 @@ int addInterestingTime(lua_State* L) {
return 0;
}
+int worldPosition(lua_State* L) {
+ ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::worldPosition");
+
+ std::string identifier = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes);
+ SceneGraphNode* node = sceneGraphNode(identifier);
+
+ if (!node) {
+ return ghoul::lua::luaError(
+ L,
+ fmt::format("Did not find a match for identifier: {} ", identifier)
+ );
+ }
+
+ glm::dvec3 pos = node->worldPosition();
+ ghoul::lua::push(L, pos);
+
+ ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
+ return 1;
+}
+
+int worldRotation(lua_State* L) {
+ ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::worldRotation");
+
+ std::string identifier = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes);
+ SceneGraphNode* node = sceneGraphNode(identifier);
+
+ if (!node) {
+ return ghoul::lua::luaError(
+ L,
+ fmt::format("Did not find a match for identifier: {} ", identifier)
+ );
+ }
+
+ glm::dmat3 rot = node->worldRotationMatrix();
+ ghoul::lua::push(L, rot);
+
+ ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
+ return 1;
+}
+
} // namespace openspace::luascriptfunctions
diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp
index c614aa14cc..b7c6b6541d 100644
--- a/src/scripting/scriptengine.cpp
+++ b/src/scripting/scriptengine.cpp
@@ -191,14 +191,23 @@ bool ScriptEngine::runScript(const std::string& script, ScriptCallback callback)
}
catch (const ghoul::lua::LuaLoadingException& e) {
LERRORC(e.component, e.message);
+ if (callback) {
+ callback(ghoul::Dictionary());
+ }
return false;
}
catch (const ghoul::lua::LuaExecutionException& e) {
LERRORC(e.component, e.message);
+ if (callback) {
+ callback(ghoul::Dictionary());
+ }
return false;
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
+ if (callback) {
+ callback(ghoul::Dictionary());
+ }
return false;
}