TOUCHDESIGNER NETWORK ARCHITECTURE

Mars Atmosphere Instrument

Real MCD/PSG atmospheric data → GPU shaders → SOMI-1 gestural control
Perform the Martian sunset with your body
TOP — Texture Operator
CHOP — Channel Operator
DAT — Data Operator
SOP — Surface Operator
COMP — Component
MAT — Material
OUT — Output
Click any node to expand its details, inputs/outputs, and code snippets
⚗️
PHASE 1 · DATA FOUNDRY
Python / PSG API / Offline Pre-computation

All scientifically accurate data is computed here, then baked into textures for real-time use.

DAT psg_api
PSG API Calls

Python Script DAT calls PSG API with MCD atmospheric profiles. Runs at project load, not per-frame.

INPUTS
→ MCD NetCDF: dust, T, P, CO₂, H₂O ice profiles
→ Location: Gusev Crater (Spirit landing site)
→ Ls range: 0°–360° in 30° steps (12 seasons)
OUTPUTS
← Sky radiance spectra at 630/530/440 nm
# PSG config for each (solar_elev, dust_tau, Ls) combo
curl -d type=rad --data-urlencode file@config.txt \
  https://psg.gsfc.nasa.gov/api.php
DAT sky_lut
Sky Radiance LUT Baker

Converts PSG spectral output into 2D lookup textures. X-axis = angle from sun (0°–180°), Y-axis = elevation (-10°–90°). RGB = radiance at 630/530/440 nm.

INPUTS
→ PSG radiance output per viewing direction
OUTPUTS
← sky_clear_sun15.exr, sky_clear_sun30.exr, sky_storm_sun15.exr, ... (N textures)
# Grid: 14 solar elevations × 4 dust states × 12 seasons
# = 672 PSG batch runs → 672 sky LUT textures
# Packed into atlas: 4×3 grid per dust state
DAT terrain_prep
Terrain Data Prep

Crops MOLA elevation data and MGS/TES albedo maps to viewport region. Outputs 16-bit heightmap and RGB albedo texture.

INPUTS
→ MOLA DEM (463m/pixel global)
→ MGS/TES thermal inertia + albedo
OUTPUTS
← terrain_height.exr (16-bit float)
← terrain_albedo.png
DAT scatter_lut
Scattering Parameter LUT

Pre-computes Mie scattering properties from PSG's models. For Mars dust (reff ~1.5μm, σ=1.5): extinction coefficient, single-scattering albedo (ω), and Henyey-Greenstein asymmetry factor (g) at each wavelength.

INPUTS
→ PSG Mie models (Bohren & Huffman)
→ HITRAN refractive indices (HRI db)
→ Dust: reff=1.5μm, Water ice: reff=3.0μm
OUTPUTS
← scatter_dust.exr — R:Qext, G:ω, B:HG_g per λ
← scatter_ice.exr — same for water ice
# Henyey-Greenstein phase function:
# P(θ) = (1 - g²) / (1 - 2g·cosθ + g²)^(3/2)
# Mars dust at 440nm: g ≈ 0.63 (strong forward)
# Mars dust at 630nm: g ≈ 0.68
🎛️
PHASE 2 · INPUT LAYER
SOMI-1 Motion Sensors + Audio Input
CHOP midi_in
MIDI In CHOP

Receives USB-MIDI from SOMI-1 hub. Each sensor sends 7 CC channels: 3 tilt (X/Y/Z), 3 acceleration (X/Y/Z), 1 activity. Two sensors = 14 CC channels.

INPUTS
→ SOMI-1 Hub via USB-MIDI
OUTPUTS
← 14 raw CC channels (0–127)
CHOP filter_chop
Filter CHOP

Smooths raw sensor data. SOMI-1 accelerometers can be jittery — apply low-pass filter. Different time constants for each mapping: solar position needs smooth/slow, dust storm trigger needs fast response.

INPUTS
→ Raw CC channels
OUTPUTS
← Smoothed CC channels
# Filter settings per channel:
# sun_elevation: filter=0.3s (smooth, deliberate)
# sun_azimuth:   filter=0.3s
# dust_opacity:  filter=0.8s (slow, geological)
# storm_trigger: filter=0.05s (fast, percussive)
CHOP math_chop
Math / Range CHOP

Remaps MIDI 0–127 to physical parameter ranges. This is where instrument design happens — the feel of the mapping.

INPUTS
→ Smoothed CC channels
OUTPUTS
← Named physical parameter channels
# SENSOR 1 (Right wrist) — Solar control
# Tilt Y  → sun_elevation:  0–127 → -5° to 90°
# Tilt X  → sun_azimuth:    0–127 → 0° to 360°
# Activity → dust_lift:     0–127 → 0.0 to 0.3 (additive)

# SENSOR 2 (Left wrist) — Atmosphere control
# Tilt Y  → dust_base_tau:  0–127 → 0.2 to 8.0 (log)
# Tilt X  → season_Ls:      0–127 → 0° to 360°
# Accel Z → storm_trigger:  threshold > 100 → bool
CHOP logic_chop
Logic CHOP

Combines dust_base_tau + dust_lift into final dust_tau. Detects storm trigger (sharp wrist snap). Clamps all values to physical ranges.

INPUTS
→ Physical parameter channels
OUTPUTS
← Final control channels: sun_elev, sun_az, dust_tau, Ls, storm_active
CHOP audio_in
Audio Device In CHOP

Captures live audio input or playback. Feed it music, ambient sound, or Martian wind recordings.

INPUTS
→ Audio interface / microphone
OUTPUTS
← Raw audio signal
CHOP audio_spectrum
Audio Spectrum CHOP

FFT analysis split into configurable bands. Three-band split mirrors PSG's approach: low (dust resonance), mid (wind), high (ice crystal scintillation).

INPUTS
→ Raw audio signal
OUTPUTS
← bass_power, mid_power, high_power
← full_spectrum (512 bins)
# Band splits:
# Bass:  20–200 Hz  → dust_opacity_mod (±0.5 tau)
# Mid:   200–2kHz   → wind_displacement (terrain shimmer)
# High:  2k–16kHz   → ice_scintillation (aureole sparkle)
🗂️
PHASE 3 · DATA / TEXTURE MANAGEMENT
Loading, Blending, and Preparing GPU Textures
TOP sky_atlas_top
Movie File In TOPs

Loads pre-baked sky LUT atlas textures. One atlas per dust state, containing multiple solar elevations tiled in a grid. 32-bit float EXR format preserves HDR radiance values.

INPUTS
→ sky_clear_atlas.exr
→ sky_moderate_atlas.exr
→ sky_heavy_atlas.exr
→ sky_storm_atlas.exr
OUTPUTS
← 4 atlas TOPs
TOP sky_blend
GLSL TOP — Sky State Blender

Takes dust_tau from CHOP, determines which two atlas textures to interpolate between. Also interpolates within atlas based on sun_elevation. Outputs a single blended sky LUT for current conditions.

INPUTS
→ 4 atlas TOPs
→ dust_tau, sun_elevation, season_Ls uniforms
OUTPUTS
← Blended sky radiance LUT (current state)
// Trilinear interpolation in parameter space:
// 1. dust_tau → blend between two nearest dust atlases
// 2. sun_elevation → sample correct tile within atlas
// 3. season_Ls → blend between seasonal variants
vec3 sky = mix(
  sampleAtlas(atlas_lo, sun_elev, angle_from_sun),
  sampleAtlas(atlas_hi, sun_elev, angle_from_sun),
  dust_frac
);
TOP terrain_top
Terrain TOPs

MOLA heightmap and TES albedo map, loaded as 32-bit float and 8-bit RGB respectively.

INPUTS
→ terrain_height.exr
→ terrain_albedo.png
OUTPUTS
← Height texture
← Albedo texture
TOP scatter_top
Scattering LUT TOP

Mie scattering parameters texture. The GLSL shader reads extinction, albedo, and HG asymmetry factor per wavelength for the current dust particle size.

INPUTS
→ scatter_dust.exr
→ scatter_ice.exr
OUTPUTS
← Dust scattering params
← Ice scattering params
CHOP uniform_bridge
CHOP To → Uniforms

Bridges all control channels to GLSL TOP uniforms. This is the handoff from the instrument layer to the render layer. Each named CHOP channel becomes a named uniform in the shader.

INPUTS
→ sun_elev, sun_az, dust_tau, Ls, storm_active
→ bass_power, mid_power, high_power
OUTPUTS
← GLSL uniforms
// In GLSL TOP → Vectors 1 page:
// u_sun_elev    ← sun_elev channel
// u_sun_az      ← sun_az channel
// u_dust_tau    ← dust_tau channel
// u_Ls          ← Ls channel
// u_audio_bass  ← bass_power channel
// u_audio_mid   ← mid_power channel
// u_audio_high  ← high_power channel
// u_storm       ← storm_active channel
🔥
PHASE 4 · RENDER PIPELINE
Multi-Pass GLSL Rendering on GPU
TOP pass1_sky
GLSL TOP — Pass 1: Sky Dome

For each pixel, compute viewing direction (elevation, azimuth relative to sun). Sample the blended sky LUT. Add audio-reactive modulation: bass thickens the atmosphere, high frequencies create scintillation near the sun.

INPUTS
→ Blended sky LUT, Scatter LUT, All uniforms
OUTPUTS
← Sky radiance buffer (HDR float32)
uniform float u_sun_elev, u_sun_az, u_dust_tau;
uniform float u_audio_bass, u_audio_high;
uniform sampler2D u_sky_lut;

void main() {
  vec2 uv = gl_FragCoord.xy / uTD2DInfos[0].res.zw;
  float view_elev = uv.y * 90.0;
  float view_az_from_sun = abs(uv.x * 360.0 - u_sun_az);
  vec2 lut_coord = vec2(
    view_az_from_sun / 180.0,
    (view_elev + 10.0) / 100.0
  );
  vec3 sky = texture(u_sky_lut, lut_coord).rgb;
  sky *= 1.0 + u_audio_bass * 0.15;
  float sun_prox = 1.0 - smoothstep(0.0, 15.0, view_az_from_sun);
  sky += sun_prox * u_audio_high * vec3(0.02, 0.03, 0.08);
  fragColor = TDOutputSwizzle(vec4(sky, 1.0));
}
TOP pass2_terrain
GLSL TOP — Pass 2: Terrain

Ray-marches into MOLA heightmap to render terrain. Applies surface albedo from TES. Lighting uses sun direction from uniforms. Atmospheric fog based on dust_tau dims distant terrain.

INPUTS
→ MOLA heightmap, TES albedo, Sun direction uniforms, dust_tau
OUTPUTS
← Terrain color + depth buffer
// Terrain ray-march with real MOLA data
// Atmospheric extinction: exp(-dust_tau * distance / H)
// H = scale height ≈ 11.1 km for Mars
// Surface illumination: Lambert * solar_irradiance
// Fog color: sample sky LUT at horizon elevation
TOP pass3_sun
GLSL TOP — Pass 3: Solar Disk

Renders the solar disk with physically correct angular size (0.35° from Mars), limb darkening, and wavelength-dependent extinction. At low sun elevations with high dust, the blue aureole emerges from Mie forward scattering.

INPUTS
→ Sun position uniforms, Scatter LUT, dust_tau
OUTPUTS
← Solar disk + aureole buffer
// Sun angular radius: 0.176° from Mars (0.35° diameter)
// Limb darkening: I(θ) = I₀(1 - u(1 - cosθ))
// Extinction: exp(-tau_total(λ) / cos(zenith))
// Blue aureole: HG phase function at small angles
//   P(θ) = (1-g²)/(1-2g·cosθ+g²)^1.5
//   At 440nm, g≈0.63 → strong forward peak → blue halo
TOP pass4_composite
GLSL TOP — Pass 4: Composite + Tonemap

Combines sky + terrain + sun. Applies physically-based tonemapping (ACES or Reinhard) to compress HDR to display range. Adds subtle dust-in-air scattering. Optional color grading toward Curiosity/Spirit camera response curves.

INPUTS
→ Sky buffer, Terrain buffer, Solar disk buffer, All uniforms
OUTPUTS
← Final composited frame (8-bit RGB)
// Composite order: sky → terrain (with depth) → sun (additive)
// Tonemapping: ACES filmic for natural roll-off
// Optional: apply Mars camera white balance
//   (Spirit/Curiosity approximate sensor response)
// Storm overlay: when storm_active, add animated
//   dust particle noise layer (u_audio_bass drives density)
📡
PHASE 5 · OUTPUT
Display / Share / Record
COMP out_display
Window COMP

Fullscreen output to projector or display. For live performance, this IS the Martian sky filling the room.

INPUTS
→ Final composited frame
OUTPUTS
← Display
TOP out_syphon
Syphon/Spout Out TOP

Shares the rendered frame with other applications in real-time on GPU. Feed into Resolume for VJ mixing, or into Ableton Live for synchronized audio-visual performance.

INPUTS
→ Final composited frame
OUTPUTS
← Syphon/Spout stream
TOP out_record
Movie File Out TOP

Records the performance to video. HAP codec for real-time playback, or ProRes for editing. Capture the entire sunset performance.

INPUTS
→ Final composited frame
OUTPUTS
← .mov / .mp4 file
TOP out_ndi
NDI Out TOP

Network video output for streaming or multi-machine setups. Send the Mars visualization over the network to other displays or streaming software.

INPUTS
→ Final composited frame
OUTPUTS
← NDI network stream
🎮 SOMI-1 → MARS PARAMETER MAPPING
SensorMotionControlsRangeGesture Feel
1 (R wrist)Tilt YSolar Elevation-5° → 90°Raise arm = raise sun
1 (R wrist)Tilt XSolar Azimuth0° → 360°Sweep arm = sweep sun across horizon
1 (R wrist)ActivityDust Lift (additive)0.0 → +0.3 τMove fast = kick up dust
2 (L wrist)Tilt YBase Dust Opacity0.2 → 8.0 τ (log)Raise arm = thicken atmosphere
2 (L wrist)Tilt XSeason (Ls)0° → 360°Rotate wrist = change season
2 (L wrist)Accel Z (snap)Storm TriggerboolSharp wrist snap = instant storm
🔊 AUDIO → ATMOSPHERIC MODULATION
Frequency BandControlsRangeVisual Effect
Bass (20–200 Hz)Dust Opacity Modulation±0.5 τKick drum thickens the air, sky reddens
Mid (200 Hz–2 kHz)Terrain Wind Shimmer0–3 px displacementHarmonic content makes terrain haze ripple
High (2–16 kHz)Ice Crystal Scintillation0–0.15 brightnessHi-hats and cymbals sparkle the solar aureole
🎭 PERFORMANCE SCENARIO
Opening: Both arms at rest. Sun high, clear sky (tau=0.3). Salmon-pink Martian sky, ochre terrain stretching to the horizon. Music begins — ambient drone.

Descent: Slowly lower right arm. Sun drops toward horizon. Path length through atmosphere grows. Sky shifts from pink to deeper amber at the horizon. The blue aureole around the sun intensifies — real Mie forward-scattering physics from PSG data.

Storm: Raise left arm gradually. Dust opacity climbs from 0.3 to 3.0. Horizon vanishes. Sky goes from salmon to sepia. Sun becomes a diffuse bright patch. Bass drops in the music thicken the air further — each kick drum pulses the opacity.

Climax: Sharp wrist snap — storm trigger fires. Tau jumps to 8.0. Near-total whiteout. Only the faintest glow where the sun was. Then slowly lower the left arm — the storm clears. As dust settles and sun sits just above the horizon, the blue sunset halo emerges sharp and pure against the butterscotch sky.

Every color, every gradient, every halo — computed by PSG from real MCD atmospheric profiles, real Mie scattering theory, real Mars dust particle sizes.
📊 DATA BUDGET
AssetSpecificationMemory / Time
Sky LUT atlases (4 dust states × 12 seasons)~48 textures @ 1024×512 EXR~96 MB
MOLA heightmap (cropped region)2048×2048 × 32-bit float~16 MB
TES albedo map (cropped)2048×2048 × RGB 8-bit~12 MB
Scattering LUT (dust + ice)256×1 × RGBA float × 2~4 KB
PSG API calls (foundry phase)~672 batch calls~2 hrs compute
Total GPU texture memory~125 MB
⚗️ FOUNDRY COMPUTATION GRID
Solar elevations: -5°, 0°, 5°, 10°, 15°, 20°, 30°, 40°, 50°, 60°, 70°, 80°, 90° (14 steps — denser near horizon where changes are dramatic)
Dust optical depth: 0.2, 0.5, 1.0, 3.0 (4 states — log-spaced, interpolate between)
Season (Ls): 0°, 30°, 60°, ... 330° (12 steps — MCD native cadence)
Viewing directions per LUT: 360 azimuth × 100 elevation = 36,000 PSG raytrace calls per state

Optimization: Use PSG's GlobES binning (factor=3 → 9× speedup). Run overnight. Cache everything. The foundry runs once — the instrument runs forever.

MVP (start here): 1 season (Ls=270, dusty) × 14 solar elevations × 2 dust states = 28 PSG batch runs. Get the sunset working first. Expand the grid later.
🔬 SCIENTIFIC DATA SOURCES
Atmosphere: Mars Climate Database (MCD v5.2+, Millour et al. 2015) — 64×49 grid, 30 layers to ~90km, dust/ice/CO₂/H₂O profiles
Radiative transfer: PSG PUMAS multiple scattering (Stamnes et al. 2000) with delta-M+ correction
Dust scattering: PSG Mie models (Bohren & Huffman 1983), reff ~1.5μm, σ=1.5 log-normal, HRI optical constants (Massie & Hervig 2013), Wolff et al. 2009 T-matrix
Terrain: MOLA topographic data (Smith et al. 2001) — 463m/pixel global DEM
Surface albedo: MGS/TES thermal emission spectrometer (Smith 2004)
Solar spectrum: SOLAR-HRS (Meftah et al. 2023) + Kurucz 2005 templates