Remix Sky API

June 28, 2026 · View on GitHub

The sky / atmosphere system exposes a plugin-facing surface through the standard Remix C API — no dedicated remixapi_SetSky function exists. Control flows through two channels documented here:

  • Direct knobs (SetConfigVariable). A plugin pushes individual rtx.atmosphere.* and rtx.sky* options per-frame (or once at startup). This is the lowest-level interface; it's how the FNV and FO4 plugins drive sun, stars, moons, and clouds today.
  • Weather preset blender (SetGameValue + GetGameValue). A higher-level layer that names twelve weather archetypes (clear, overcast, thunderstorm, …) and transitions smoothly between them. The blender writes into the same rtx.atmosphere.* knobs the direct surface exposes, so the two layers compose naturally.

For the channels themselves, see RemixApi.md and RemixApi.md. For the fork-side implementation, see rtx_fork_atmosphere.cpp, rtx_fork_atmosphere.h, rtx_fork_weather.cpp, and rtx_fork_weather.h.

Format conventions

Plugin-side: SetConfigVariable(key, value) where value is a string.

  • float"%.4f" (e.g. "15.0000")
  • bool"True" or "False"
  • Vector3"x, y, z" (e.g. "0.85, 0.87, 0.92")
  • uint32_t → decimal (e.g. "0", "1")

NoSave = ✓ means the option is excluded from user.conf serialization on shutdown — safe to push every frame from a game plugin without polluting the user's config file.

Layer 1 — Direct rtx.atmosphere.* knobs

Mode switch

KeyTypeDefaultNotes
rtx.skyModeint0Sky rendering mode. 0 = SkyboxRasterization (traditional skybox); 1 = Numos (Hillaire scattering). All rtx.atmosphere.* options below only take effect in mode 1.

Sun pose (game-driven, push every frame)

These persist to user.conf (no NoSave flag), but a plugin driving time-of-day should push them every frame — the last write wins.

KeyTypeDefaultNotes
rtx.atmosphere.sunElevationfloat15.0Sun angle from horizon, degrees. -90 to +90.
rtx.atmosphere.sunRotationfloat0.0Sun azimuth (rotation around zenith), degrees. 0–360.

Sun appearance (persistent)

KeyTypeDefaultNotes
rtx.atmosphere.sunSizefloat0.545Sun disc angular diameter, degrees.
rtx.atmosphere.sunIntensityfloat1.0Sun brightness multiplier.
rtx.atmosphere.sunIlluminanceVector320, 20, 20Base illuminance color/intensity (multiplied by sunIntensity).

Atmosphere physical properties (persistent)

KeyTypeDefaultNotes
rtx.atmosphere.altitudefloat100.0Camera altitude above sea level, meters.
rtx.atmosphere.airDensityfloat1.0Air molecule density multiplier (1 = clear sky).
rtx.atmosphere.aerosolDensityfloat1.0Aerosol/dust density multiplier (1 = typical haze).
rtx.atmosphere.ozoneDensityfloat1.0Ozone layer density multiplier (1 = typical).
rtx.atmosphere.planetRadiusfloat6371.0Planet radius, km. Affects horizon curvature in atmospheric math.
rtx.atmosphere.atmosphereThicknessfloat100.0Atmosphere thickness, km.
rtx.atmosphere.mieAnisotropyfloat0.97Mie phase g parameter, -1 to 1. Controls haze forward-scatter.
rtx.atmosphere.rayleighScatteringVector30.0058, 0.0135, 0.0331Base Rayleigh scattering coefficients, km⁻¹.
rtx.atmosphere.mieScatteringVector30.003996, 0.003996, 0.003996Base Mie scattering coefficients, km⁻¹.
rtx.atmosphere.ozoneAbsorptionVector30.00204, 0.00497, 0.000214Base ozone absorption coefficients, km⁻¹.
rtx.atmosphere.ozoneLayerAltitudefloat25.0Ozone layer peak altitude, km.
rtx.atmosphere.ozoneLayerWidthfloat15.0Ozone layer thickness, km.

Stars — pose & rotation (game-driven, push every frame)

These persist to user.conf (no NoSave flag), but a time-of-day plugin should push them every frame alongside the sun pose.

KeyTypeDefaultNotes
rtx.atmosphere.starRotationfloat0.0Sidereal sky rotation angle, degrees, 0–360. The entire star pattern rotates as one rigid body around the celestial pole.
rtx.atmosphere.starBrightnessfloat0.5Overall star brightness multiplier. Fade to 0 at sunrise, restore at sunset.

Stars — celestial pole (persistent, set once at startup or via rtx.conf)

KeyTypeDefaultNotes
rtx.atmosphere.starAxisElevationfloat90.0Celestial pole elevation from horizon, degrees. 90 = pole at zenith (default, behavior matches pre-rotation). Set to the game world's latitude for a realistic star trail.
rtx.atmosphere.starAxisRotationfloat0.0Celestial pole azimuth, degrees (0 = North). Only relevant when starAxisElevation != 90.

Night sky appearance (persistent)

KeyTypeDefaultNotes
rtx.atmosphere.starDensityfloat0.5Star density linear-feel slider: 0 = no stars, 1 = maximum. Mapped internally via pow(x,4)*0.05. 0.5 ≈ 0.3% of cells lit; 1.0 ≈ 5%.
rtx.atmosphere.starTwinkleSpeedfloat1.0Twinkle animation speed. 0 = static.
rtx.atmosphere.starPsfSharpnessfloat20.0PSF Gaussian exponent controlling per-star disc spread. Lower = softer, wider stars. Useful range 8–30.
rtx.atmosphere.starCloudExtinctionPowerfloat2.5Power exponent applied to cloud transmittance when extincting stars. Raises the effective opacity so bright pinpoints die inside thick cumulus. 1.0 = standard composite.
rtx.atmosphere.starAmbientCouplingStrengthfloat0.005How strongly starlight/airglow couples into cloud-march night ambient. 0 disables.
rtx.atmosphere.nightSkyBrightnessfloat0.008Ambient airglow and zodiacal-light brightness.
rtx.atmosphere.nightSkyColorVector30.15, 0.2, 0.4Airglow color tint.
rtx.atmosphere.milkyWayEnabledboolFalseMaster toggle for the galactic-band Milky Way overlay. Opt-in; off by default.
rtx.atmosphere.milkyWayDensityBoostfloat0.3Extra star density inside the galactic band when Milky Way is enabled.
rtx.atmosphere.milkyWayBackgroundBrightnessfloat0.05Diffuse background glow of the band (unresolved stars + dust).
rtx.atmosphere.milkyWayBackgroundColorVector30.5, 0.55, 0.75Outer-edge band tint (cool blue periphery).
rtx.atmosphere.milkyWayCoreColorVector31.0, 0.85, 0.55Galactic-centre tint (warm yellow-cream).
rtx.atmosphere.milkyWayDustColorVector30.15, 0.08, 0.05Dust-lane tint (dark red-brown patches).
rtx.atmosphere.milkyWayDustAmountfloat0.6Dust-lane contrast strength. 0 = smooth band, 1 = full contrast.

Per-moon options

4 moons available. Replace N with 0, 1, 2, or 3 in both the category segment AND the trailing field suffix (the suffix is part of how the options are declared via macro expansion — moon0.enabled0 etc.).

Moon pose (game-driven, push every frame)

These persist to user.conf (no NoSave flag), but a time-of-day plugin should push them every frame.

KeyTypeDefaultNotes
rtx.atmosphere.moonN.elevationNfloat45.0Moon angle from horizon, degrees. -90 to +90.
rtx.atmosphere.moonN.rotationNfloat90.0Moon azimuth (rotation around zenith), degrees. 0–360.
rtx.atmosphere.moonN.phaseNfloat0.5Lunar phase: 0 = new moon, 0.5 = full, 1.0 = new again.

Moon appearance (persistent)

Core per-moon visual properties:

KeyTypeDefaultNotes
rtx.atmosphere.moonN.enabledNboolFalseEnable this moon. Must be set True for the moon to render. All moons are off by default — opt in per-game.
rtx.atmosphere.moonN.angularRadiusNfloat3.5Angular diameter, degrees.
rtx.atmosphere.moonN.brightnessNfloat1.0Brightness multiplier. 1.0 = physical neutral; raise for stylized scenes.
rtx.atmosphere.moonN.colorNVector30.12, 0.12, 0.12Surface albedo. Default ≈ Earth's lunar Bond albedo; raise per-channel for tinted moons.
rtx.atmosphere.moonN.surfaceStyleNuint320Surface preset: 0 = Rocky, 1 = Volcanic.
rtx.atmosphere.moonN.craterDensityNfloat1.0Crater density multiplier [0, 1].
rtx.atmosphere.moonN.surfaceContrastNfloat1.0Surface light/dark contrast multiplier.
rtx.atmosphere.moonN.surfaceNoiseScaleNfloat1.0Surface feature size multiplier.
rtx.atmosphere.moonN.darkSideBrightnessNfloat0.005Dark-side brightness as fraction of the lit side.
rtx.atmosphere.moonN.roughnessAmountNfloat1.0Micro-detail surface roughness amplitude.

World-lighting strength controls (shared across all moons):

KeyTypeDefaultNotes
rtx.atmosphere.moonNeeStrengthfloat1.0Master multiplier on all direct moon lighting paths (surface NEE + clouds + volumetric). 0 = moon does not light the world.
rtx.atmosphere.moonAtmosphericCouplingStrengthfloat1.0Sky-side multiplier on the moon's contribution to atmospheric scattering. 0 = no atmospheric blue-dome around the moon.
rtx.atmosphere.surfaceMoonBrightnessfloat50.0Per-path stylistic multiplier on surface ground-moonlight NEE. Default tuned for the FNV tonemapper; 1.0 = physically pure (very dim).
rtx.atmosphere.cloudMoonBrightnessfloat2.0Per-path stylistic multiplier on cloud directional moonlight + ambient airglow.
rtx.atmosphere.haloMoonBrightnessfloat15.0Per-path stylistic multiplier on the moon disc halo Gaussian glow.

Moon cloud-look and halo shape constants:

KeyTypeDefaultNotes
rtx.atmosphere.moonCloudDiffuseGainfloat0.10Lambert diffuse weight for off-axis cloud illumination. Lower = stronger contrast.
rtx.atmosphere.moonCloudPhaseGainfloat1.0HG phase weight for peak silver-lining intensity directly in front of the moon.
rtx.atmosphere.moonCloudAnisotropyfloat0.85HG anisotropy for cloud-moon forward scatter. Higher = sharper silver-lining peak.
rtx.atmosphere.moonSilverLiningIntensityfloat1.0Master multiplier on the combined cloud-moon silver-lining term.
rtx.atmosphere.moonHaloMagnitudefloat0.0015Disc halo Gaussian shape strength. Use haloMoonBrightness for tonemapper correction, this for the shape.
rtx.atmosphere.moonHaloGlowStrengthfloat1.0Master multiplier on the combined halo + ambient airglow contribution.
rtx.atmosphere.moonAmbientAirglowfloat0.0015Ambient airglow per-moon contribution to the cloud night-light term.

Clouds (procedural volumetric layer)

A volumetric cloud layer rendered with the Nubis Cubed evaluator. Density is FBM noise gated by cloudCoverageMean; lighting is multi-scatter Nubis-Cubed with voxel-grid terrain shadows and a per-moon night ambient. Clouds composite on top of stars, moons, and atmosphere, and dim the ground via the sun-transmittance path when overcast.

Cloud weather (game-driven, push every frame)

The primary coverage knob is cloudCoverageMean. The old cloudCoverage key from earlier plugin code no longer exists — update callers to push cloudCoverageMean instead. These persist to user.conf (no NoSave flag) but should be pushed every frame from a weather-driving plugin.

KeyTypeDefaultNotes
rtx.atmosphere.cloudCoverageMeanfloat0.85Mean cloud coverage across the sky [0, 1]: 0 = clear, 1 = overcast. Primary game-weather knob.
rtx.atmosphere.cloudCoverageSpreadfloat1.0Spatial variation amplitude for coverage [0, 1]. 0 = uniform sky, 1 = full patchy range.
rtx.atmosphere.cloudCoverageNoiseScalefloat0.0033Spatial frequency of the coverage noise. Smaller = larger coverage patches.

Cloud appearance (persistent)

KeyTypeDefaultNotes
rtx.atmosphere.cloudEnabledboolTrueMaster switch for the procedural cloud layer.
rtx.atmosphere.cloudDensityfloat1.65Cloud opacity/density multiplier. Scales extinction along the march.
rtx.atmosphere.cloudAltitudefloat1.3Cloud-layer base altitude, km.
rtx.atmosphere.cloudColorVector30.89, 0.92, 1.0Base cloud albedo. Tint away from white for stylized color grading.
rtx.atmosphere.cloudWindSpeedfloat0.02Cloud drift speed, km/s. Wind offset accumulates from elapsed time.
rtx.atmosphere.cloudWindDirectionfloat45.0Wind direction, degrees. 0 = +X, 90 = +Z.
rtx.atmosphere.cloudShadowStrengthfloat1.0How strongly overcast clouds dim ground and atmosphere lighting [0, 1]. 1 = full voxel-grid contribution; 0 = shadows muted.
rtx.atmosphere.cloudAnisotropyfloat0.6Henyey-Greenstein g for cloud forward-scatter (silver lining).

Cloud volumetric & polish (advanced — persistent)

Ray-march quality:

KeyTypeDefaultNotes
rtx.atmosphere.cloudViewSamplesuint3232Ray-march steps through the cloud slab. Range 1–32. Higher = better quality, higher cost.
rtx.atmosphere.cloudThicknessfloat2.75Vertical depth of the cloud slab, km.
rtx.atmosphere.cloudCurvaturefloat0.38Sky-dome curvature for the cloud sphere: 0 = real-planet radius (nearly flat ceiling), 1 = tight dome. Does not affect atmospheric math.

Shadow and color polish:

KeyTypeDefaultNotes
rtx.atmosphere.cloudShadowTintVector30.55, 0.65, 0.85Sky-blue bounce color applied on the shadow side of clouds.
rtx.atmosphere.cloudShadowTintStrengthfloat1.0Strength of the shadow tint contribution [0, 1].
rtx.atmosphere.cloudSunsetWarmthfloat0.95Warm tint strength on the sunward side at low sun angles. 0 = disabled.
rtx.atmosphere.cloudVoxelShadowsEnableboolTrueUse the D_sun voxel grid for cumulus-shaped cloud-on-terrain shadows at NEE entry points. Replaces the legacy uniform coverage proxy.
rtx.atmosphere.cloudShadowMarchStrengthfloat1.0Beer-Lambert exponent multiplier inside the voxel-grid shadow lookup. Higher = darker cumulus shadows on terrain. Only active when cloudVoxelShadowsEnable is on.
rtx.atmosphere.cloudShadowFactorStrengthfloat4.0Post-denoise pow exponent on the per-pixel cloud shadow factor at composite time. 1.0 = unchanged; higher deepens shadow contrast without re-baking the voxel grid.

Aerial perspective (distant cloud softening):

KeyTypeDefaultNotes
rtx.atmosphere.cloudAerialHazePerKmfloat0.05Per-km haze extinction on cloud radiance. Dims distant samples toward atmospheric color (softness). Does not eliminate the horizon white-wall alone.
rtx.atmosphere.cloudAerialFadePerKmfloat0.15Per-km fade extinction on cloud alpha accumulation. Prevents horizon-grazing rays from building a solid white wall.

Volumetric sky-ambient:

KeyTypeDefaultNotes
rtx.atmosphere.cloudSkyAmbientStrengthfloat0.0Strength of sky-view LUT radiance injected into the volumetric froxel pass [0, 3]. 0 = feature disabled (default-off). 1 = physical baseline. Requires rtx.skyMode = 1.
rtx.atmosphere.cloudSkyAmbientCloudOcclusionStrengthfloat1.0Strength of cloud occlusion on the sky-ambient term [0, 1]. 1 = full physical occlusion; 0 = debug only.

Nubis Cubed lighting equations:

KeyTypeDefaultNotes
rtx.atmosphere.cloudRenderRTEnableboolTrueUse the Nubis Cubed cloud render RT for primary sky-miss rays. Indirect/PSR/reflection rays continue to use analytical evalClouds.
rtx.atmosphere.cloudMultiScatterStrengthfloat1.0Master multiplier on Wrenninge multi-scatter sun response. 1.0 = Hillaire/Frostbite baseline.
rtx.atmosphere.cloudMultiScatterOctavesuint323Wrenninge octave count [1, 4]. 1 = single anisotropic term (no multi-scatter).
rtx.atmosphere.cloudMsScalefloat1.0Multiplier on the Nubis Cubed sigma_ms remap term [0, 2]. Higher brightens cumulus bottoms.
rtx.atmosphere.cloudPhaseG1float0.8Primary HG asymmetry — strong forward-scatter, drives silver lining at backlit edges.
rtx.atmosphere.cloudPhaseG2float0.3Secondary HG asymmetry — broader in-scatter envelope.
rtx.atmosphere.cloudMsSunDotMaxfloat0.9Nubis Cubed sigma_ms remap upper bound on sun_dot.
rtx.atmosphere.cloudMsSigmaShallowfloat0.25Nubis Cubed sigma_ms at cloud surface / shallow penetration.
rtx.atmosphere.cloudMsSigmaDeepfloat0.05Nubis Cubed sigma_ms deep inside cloud.
rtx.atmosphere.cloudMsSdfDepthfloat128.0SDF depth (meters) at which sigma_ms saturates to the deep value.

Cloud spatial variation (Nubis-style type/coverage regions):

KeyTypeDefaultNotes
rtx.atmosphere.cloudTypeMeanfloat0.75Mean cloud type [0, 1]: 0 = stratus, 0.5 = stratocumulus, 1 = cumulus.
rtx.atmosphere.cloudTypeSpreadfloat0.5Spatial variation amplitude for cloud type [0, 1].
rtx.atmosphere.cloudTypeNoiseScalefloat0.001Spatial frequency for type noise. Smaller = larger type-region features.
rtx.atmosphere.cloudAnvilBiasfloat0.3Cumulus anvil top inflation [0, 1]. 0 = flat tops, 1 = mushroom-cap spread.

Cloud noise bake (changes apply on game relaunch):

KeyTypeDefaultNotes
rtx.atmosphere.cloudNoiseTileKmfloat12.0World-space tile period (km) for the 3D cloud noise texture. Smaller = more visible tiling. Relaunch required.
rtx.atmosphere.cloudWorleyCarveStrengthfloat0.6Worley FBM carve strength subtracted from the Perlin base. 0 = smooth blobs; 1 = aggressive cell silhouettes. Relaunch required.
rtx.atmosphere.cloudWorleyFrequencyfloat1.0Worley feature-point density, cycles per km. Smaller = larger cumulus cells. Relaunch required.
rtx.atmosphere.cloudWorleyOctavesuint323Worley FBM octave count [1, 4]. Relaunch required.

Height LUT and two-layer clouds:

KeyTypeDefaultNotes
rtx.atmosphere.cloudHeightLutEnableboolTrueUse a 64×128 baked height LUT for per-altitude cloud shape instead of the procedural trapezoid. Only affects the screen-space cloud render pass.
rtx.atmosphere.cloudLayer2EnableboolTrueEnable a second cloud slab (cirrus deck by default) composited on top of the primary cumulus layer.
rtx.atmosphere.cloudLayer2Altitudefloat5.5Base altitude (km) of the second slab.
rtx.atmosphere.cloudLayer2Thicknessfloat2.0Vertical depth (km) of the second slab.
rtx.atmosphere.cloudLayer2TypeMeanfloat0.6Mean cloud type for layer 2 [0, 1]. Low values produce stratus/cirrus shapes.
rtx.atmosphere.cloudLayer2TypeSpreadfloat1.0Cloud-type variation for layer 2. Independent of layer 1.
rtx.atmosphere.cloudLayer2CoverageMeanfloat0.85Mean coverage for layer 2 [0, 1].
rtx.atmosphere.cloudLayer2CoverageSpreadfloat0.0Coverage variation for layer 2. Independent of layer 1.
rtx.atmosphere.cloudLayer2DensityScalefloat0.65Per-step density multiplier for layer 2. Keep low for optically-thin cirrus.
rtx.atmosphere.cloudLayer2NoiseSeedfloat1000.0Seed offset for layer 2 coverage/type noise. Any non-zero value decorrelates it from layer 1's pattern.

Layer 2 — Weather preset blender (__weather.*)

The weather system exposes a fork-side preset blender that drives the same rtx.atmosphere.* knobs above through a higher-level preset abstraction.

The three surfaces

SurfaceChannelKey prefixWho writes
Trigger transitionsSetGameValue__weather.target, __weather.blend_secondsGame / plugin
Read statusGetGameValue__weather.current, __weather.previous, __weather.blend_progressGame / plugin reads; fork writes
Tune presetsSetConfigVariablertx.weather.preset.<name>.<field>Modder / plugin (mostly via user.conf)

Surface 1 — Trigger transitions

Setting __weather.target to a known preset name activates the blender. The blender lerps every weather field from the previous preset to the new one over __weather.blend_seconds (default 1.0).

// Example: switch to thunderstorm over 5 seconds
iface.SetGameValue("__weather.blend_seconds", "5.0");
iface.SetGameValue("__weather.target",        "thunderstorm");
KeyTypeDefaultMeaning
__weather.targetstring (preset name)absentTarget preset to blend toward. Setting to an unknown name logs a warning and the blender goes dormant. Clear by setting to "".
__weather.blend_secondsfloat-as-string"1.0"Blend duration. Clamped to >= 0.001.
__weather.drift_speedfloat-as-string"1.0"Cloud-drift phase advance multiplier. Higher = faster evolution. 0 freezes drift. Smoothed inside the renderer with tau = 1.0s.
__weather.drift_intensityfloat-as-string"1.0"Cloud-drift swing amplitude multiplier. 0 disables drift entirely. Smoothed inside the renderer with tau = 1.0s.

Setting target mid-blend retargets cleanly: the partial blend state becomes the new "previous" snapshot, and the timer restarts toward the new target.

The blender is dormant when __weather.target is absent or unknown — there is zero behavioral change for runs that do not opt in.

Surface 2 — Read status

Once the blender is active, it publishes its state back to the GameStateStore each frame:

KeyTypeMeaning
__weather.currentstringCurrently-targeted preset name.
__weather.previousstringPreset being blended from.
__weather.blend_progressfloat-as-string, 0.01.0Fraction of the blend completed. 1.0 once the target is reached.

Read with the standard two-call sized GetGameValue pattern:

char buf[64];
uint32_t actual = 0;
iface.GetGameValue("__weather.blend_progress", buf, sizeof(buf), &actual);
if (actual > 0 && actual <= sizeof(buf)) {
    float progress = strtof(buf, NULL);
    // ...
}

Surface 3 — Tune presets

Each preset has 42 RTX_OPTIONs declared under rtx.weather.preset.<name>.<field> — generated from a single X-macro at rtx_fork_weather.h.

// Example: make 'foggy' fog denser
iface.SetConfigVariable("rtx.weather.preset.foggy.aerosolDensity",                       "3.0");
iface.SetConfigVariable("rtx.weather.preset.foggy.transmittanceMeasurementDistanceMeters", "40.0");

Or, equivalently, in user.conf with no code at all:

rtx.weather.preset.foggy.aerosolDensity = 3.0
rtx.weather.preset.foggy.transmittanceMeasurementDistanceMeters = 40.0

Modder workflow — retune what each archetype looks like — is the intended use of this surface. Per-frame tuning from a game is unusual; prefer Surface 1 + a custom preset.

Preset names

The 12 valid values for __weather.target:

PresetDescription
clearSunny, crisp, low haze
partlyCloudyLight scattered clouds
overcastDefault look — uniform cloud cover
hazyWarm summer haze
foggyHeadline fog preset, low visibility
drizzleLight rain, medium fog
rainstormHeavy clouds, dim sun, dense fog
thunderstormHeaviest, bruised tone
snowMedium clouds, cool fog
blizzardWhiteout, severe visibility loss
sandstormYellow-orange forward-scattering fog
smoggyIndustrial dark grey-brown haze

Per-preset field list (42 fields)

Single source of truth: WEATHER_PRESET_FIELD_LIST in rtx_fork_weather.h. Adding a field there propagates to all 12 presets, the WeatherSnapshot struct, and the blender automatically.

The full 348-row table of (preset × field → value) lives in RtxOptions.md under the rtx.weather.preset.* namespace. For the per-field neutral defaults and the field categories (Cloud / Atmosphere / Sky-mood / Volumetric), see the field-list X-macro in the header.

How the two layers compose

When both layers are active, the weather blender writes the same rtx.atmosphere.* values that a direct SetConfigVariable push would. Both layers ultimately drive the same RTX_OPTIONs, so the runtime applies last-writer-wins per frame.

A plugin that wants weather presets as a baseline plus selective overrides should: (1) set __weather.target to drive the bulk of the sky, and (2) push specific rtx.atmosphere.* keys after the GameStateStore tick each frame to override individual knobs. The override pushes win because they happen later in the frame.

Concrete examples

Enable moon 0 once at startup

static bool moon0Enabled = false;
if (!moon0Enabled) {
  if (RemixRenderer::SetConfigVariable("rtx.atmosphere.moon0.enabled0", "True")) {
    moon0Enabled = true;
  }
}

Drive sun + moon 0 from in-game time

const float hour = cachedGameHour->value;
const float kPi = 3.14159265358979323846f;

// Sun: peaks at noon, dips below horizon at night
const float sunElev = std::sin((hour - 6.0f) / 12.0f * kPi) * 90.0f;
const float sunRot  = (hour / 24.0f) * 360.0f;
PushFloat("rtx.atmosphere.sunElevation", sunElev);
PushFloat("rtx.atmosphere.sunRotation",  sunRot);

// Moon 0: opposite the sun
PushFloat("rtx.atmosphere.moon0.elevation0", -sunElev);
PushFloat("rtx.atmosphere.moon0.rotation0",  std::fmod(sunRot + 180.0f, 360.0f));
PushFloat("rtx.atmosphere.moon0.phase0",     0.5f);  // full moon for now

Rotating star field synced to game time, with sunrise/sunset fade

// Sidereal rotation: full sweep over the in-game day, in lock-step with sun.
const float starRot = std::fmod(sunRot, 360.0f);  // simplest: same rate as sun
PushFloat("rtx.atmosphere.starRotation", starRot);

// Fade stars out as the sun climbs above the horizon.
const float kStarMaxBrightness = 8.0f;  // matches default
const float fadeT = std::clamp((sunElev - 6.0f) / 6.0f, 0.0f, 1.0f);
const float starBright = kStarMaxBrightness * (1.0f - fadeT);
PushFloat("rtx.atmosphere.starBrightness", starBright);

// One-time pole config (do this on first successful weather push, then never again).
static bool poleConfigured = false;
if (!poleConfigured) {
  if (RemixRenderer::SetConfigVariable("rtx.atmosphere.starAxisElevation", "42.0") &&
      RemixRenderer::SetConfigVariable("rtx.atmosphere.starAxisRotation",  "0.0")) {
    poleConfigured = true;
  }
}

Drive cloud coverage from in-game weather

const float coverageCurrent  = weatherCloudiness(currentWeather);   // 0..1
const float coverageOutgoing = weatherCloudiness(outgoingWeather);  // 0..1
const float coverage = std::lerp(coverageOutgoing, coverageCurrent,
                                 weatherTransition);  // 0..1
PushFloat("rtx.atmosphere.cloudCoverageMean", coverage);

Trigger a weather preset from C

#include "remix/remix_c.h"
#include <stdio.h>
#include <stdlib.h>

void trigger_rainstorm(remixapi_Interface* iface) {
    iface->SetGameValue("__weather.blend_seconds", "3.0");
    iface->SetGameValue("__weather.target",        "rainstorm");
}

float poll_blend_progress(remixapi_Interface* iface) {
    char buf[32];
    uint32_t actual = 0;
    if (iface->GetGameValue("__weather.blend_progress", buf, sizeof(buf), &actual) != REMIXAPI_ERROR_CODE_SUCCESS)
        return 0.0f;
    if (actual == 0 || actual > sizeof(buf))
        return 0.0f;
    return strtof(buf, NULL);
}

Example string conversions

// float
char buf[32]; std::snprintf(buf, sizeof(buf), "%.4f", value);
SetConfigVariable("rtx.atmosphere.sunElevation", buf);

// bool
SetConfigVariable("rtx.atmosphere.moon0.enabled0", "True");

// Vector3
char vbuf[64];
std::snprintf(vbuf, sizeof(vbuf), "%.4f, %.4f, %.4f", c.r, c.g, c.b);
SetConfigVariable("rtx.atmosphere.moon0.color0", vbuf);

// uint32
SetConfigVariable("rtx.atmosphere.moon0.surfaceStyle0", "1");  // Volcanic

Bridge support

Both SetGameValue / GetGameValue and SetConfigVariable are wired through the 32-bit ↔ 64-bit bridge (see bridge/src/client/remix_api.cpp), so 32-bit games using the bridge path get the same sky / weather control as 64-bit native consumers. No special bridge call needed.

Notes

  • The fork's developer ImGui surface (Atmosphere and Weather panels in the Remix UI) drives the same rtx.atmosphere.* and __weather.* keys — there is no privileged in-engine path. Plugins and the dev UI share state through GameStateStore and the RtxOption registry.
  • The __ prefix is the convention for fork-side game-state keys read by C++ subsystems. Plugin-private keys without the prefix are fine, but use the prefix when collaborating with fork-side systems.
  • The WeatherSnapshot struct (auto-generated members from the same X-macro) is the in-memory representation the blender uses internally. It is not exposed through the C API — plugins drive the system by string keys only.

See also