Skip to content

Visual Renderables & Trails

Once a SceneGraphNode is positioned in space, its Renderable block determines how it appears visually. Below are the most common renderable types used in custom show assets.


3D Models (RenderableModel)

OpenSpace supports .obj, .fbx, .gltf, .glb, and .dae meshes via Assimp.

Renderable = {
    Type = "RenderableModel",
    GeometryFile = asset.localResource("spacecraft.glb"),
    ModelScale = 1.0,                 -- Adjust if exported in cm/km instead of meters
    EnableFaceCulling = true,
    LightSources = {
        {
            Identifier = "Sun",
            Type = "SceneGraphLightSource",
            Node = "Sun",
            Intensity = 1.0
        }
    }
}

Fixing Dark or Invisible Models

If a custom 3D model loads completely black, verify two things: (1) a LightSources block referencing "Sun" (or a CameraLightSource) is included, and (2) the model's scale isn't microscopic (0.001) or inverted inside-out (EnableFaceCulling = false helps diagnose flipped normals).


Image Planes & Billboards

Use image planes for mission patches, deep-sky astrophotography, or surface callout markers:

  • RenderablePlaneImageLocal: Renders a flat textured quad oriented in 3D space (ideal for deep-sky plates aligned to celestial coordinates).
  • Camera-Facing Billboards: Set Billboard = true (or use RenderableScreenSpaceImageLocal for HUD overlays) so labels and icons always face the viewer regardless of camera orbit angle.
Renderable = {
    Type = "RenderablePlaneImageLocal",
    Size = 50000,                     -- Width/Height in meters
    Texture = asset.localResource("nebula_plate.png"),
    BlendMode = "Additive",           -- "Normal" for opaque, "Additive" for glowing astronomical imagery
    Billboard = false
}

Orbital Trails (RenderableTrailTrajectory vs. RenderableTrailOrbit)

OpenSpace distinguishes between fixed-window trajectories (spacecraft missions with a start and end date) and closed/periodic orbits (planets, moons, and satellites):

Draws a path between explicit StartTime and EndTime bounds—required for SpiceTranslation spacecraft:

Renderable = {
    Type = "RenderableTrailTrajectory",
    Translation = {
        Type = "SpiceTranslation",
        Target = "JUNO",
        Observer = "JUPITER BARYCENTER"
    },
    Color = { 0.95, 0.55, 0.15 },
    StartTime = "2016 JUL 05 00:00:00",
    EndTime = "2025 SEP 15 00:00:00",
    SampleInterval = 3600,        -- Resolution in seconds (smaller = smoother curves)
    LineWidth = 2.5
}

Draws a continuous closed-loop trail with a fading tail behind an orbiting body:

Renderable = {
    Type = "RenderableTrailOrbit",
    Translation = {
        Type = "GPTranslation",
        TLEFile = asset.localResource("iss.tle")
    },
    Color = { 0.2, 0.8, 1.0 },
    Period = 5560,                -- Full orbital period in seconds (~92.6 min for ISS)
    Resolution = 200,             -- Number of vertices along the orbit
    LineFade = 0.75               -- 0.0 = solid ring, 1.0 = full gradient fade
}

Screenshot Placeholder: trail-renderables-comparison.png

  • Crop: Capture a side-by-side or annotated viewport comparison showing a RenderableTrailOrbit with LineFade active versus a multi-year RenderableTrailTrajectory curve.
  • Callouts: (1) Active spacecraft position node, (2) SampleInterval curve smoothness, (3) LineFade gradient tail.

Labels (RenderableLabel)

Attach floating text labels as child nodes of planets, landmarks, or spacecraft so their visibility can be toggled independently in the Scene tree:

local LabelNode = {
    Identifier = "DemoLandmark_Label",
    Parent = "DemoLandmark",
    Renderable = {
        Type = "RenderableLabel",
        Text = "Adler Planetarium",
        FontSize = 32,
        Color = { 1.0, 1.0, 1.0 },
        MinMaxSize = { 8, 48 }        -- Clamps screen-space pixel size across zoom levels
    }
}