TV5: Terrain Local Probe Lighting
Epic TV5 from docs/plans/2026-03-16-terrain-viz-epics.md is implemented on main as a terrain-local diffuse + reflection probe workflow. TV5.1 and TV5.2 ship through diffuse irradiance probes, and TV5.3 adds local reflection probes that reuse the same placement discipline for terrain-local specular.
What shipped
Public terrain control surface:
ProbeSettingsinpython/forge3d/terrain_params.pyHeightfield analytical bake path:
HeightfieldAnalyticalBakerinsrc/terrain/probes/heightfield_baker.rsHeightfield analytical reflection bake path:
HeightfieldReflectionBakerinsrc/terrain/probes/reflection_baker.rsProbe placement and rebake path:
src/terrain/renderer/probes.rsGPU packing and upload path:
src/terrain/probes/gpu.rsTerrain shader integration:
src/shaders/terrain_probes.wgslincluded bysrc/shaders/terrain_pbr_pom.wgslProbe memory reporting:
TerrainRenderer.get_probe_memory_report()Example/demo coverage:
examples/terrain_tv5_probe_lighting_demo.pyRegression coverage:
tests/test_terrain_probes.py
Public API
import forge3d as f3d
from forge3d.terrain_params import (
PomSettings,
ProbeSettings,
ReflectionProbeSettings,
make_terrain_params_config,
)
config = make_terrain_params_config(
size_px=(1280, 720),
terrain_span=2400.0,
z_scale=1.6,
cam_radius=3600.0,
cam_phi_deg=138.0,
cam_theta_deg=58.0,
ibl_enabled=True,
ibl_intensity=3.0,
probes=ProbeSettings(
enabled=True,
grid_dims=(6, 6),
height_offset=5.0,
ray_count=48,
sky_color=(0.6, 0.75, 1.0),
sky_intensity=1.0,
),
reflection_probes=ReflectionProbeSettings(
enabled=True,
grid_dims=(4, 4),
height_offset=5.0,
ray_count=16,
ground_color=(0.22, 0.18, 0.14),
strength=1.0,
),
pom=PomSettings(False, "Occlusion", 0.0, 1, 1, 0, False, False),
)
params = f3d.TerrainRenderParams(config)
frame = renderer.render_terrain_pbr_pom(
material_set=material_set,
env_maps=ibl,
params=params,
heightmap=heightmap,
)
memory = renderer.get_probe_memory_report()
Workflow notes
ProbeSettings(enabled=False)andprobes=Nonepreserve the pre-TV5 IBL-only baseline.ReflectionProbeSettings(enabled=False)andreflection_probes=Nonepreserve the pre-TV5 specular baseline.Default probe config is disabled, with
grid_dims=(8, 8),height_offset=5.0,ray_count=64,sky_color=(0.6, 0.75, 1.0), andsky_intensity=1.0.Default reflection probe config is disabled, with
grid_dims=(4, 4),height_offset=5.0,ray_count=16,ground_color=(0.22, 0.18, 0.14), andstrength=1.0.When
originandspacingare omitted, placement auto-spans the terrain bounds. A1x1grid collapses to a centered single probe.Enabled probes validate
grid_dims >= (1, 1), total probe count<= 4096,ray_count >= 1, positive explicit spacing, non-negative blend distance, and non-negative sky intensity.Enabled reflection probes validate the same placement rules with a tighter probe-count limit of
<= 256and an explicitstrengthrange of[0, 1].Probe positions are resolved from the terrain heightfield with bilinear height sampling plus
height_offset.Probe payloads are baked as SH L2 coefficients, packed into
GpuProbeData, uploaded once per cache key, and sampled with bilinear grid interpolation in the terrain shader.Reflection payloads are baked as directional local-environment face colors, packed into
GpuReflectionProbeData, uploaded once per cache key, and sampled in the terrain shader to replace the local specular term where probes are present.The diffuse probe term is blended against the existing IBL diffuse term. Outside probe coverage, the shader falls back smoothly to the old IBL behavior.
The reflection probe term is blended against the existing global specular IBL term. Outside probe coverage, terrain specular falls back smoothly to the old IBL behavior.
fallback_blend_distancedefaults to2 * min(spacing_x, spacing_y)when omitted.Rebake invalidation keys include terrain span,
z_scale, full heightfield contents and dimensions,grid_dims,origin,spacing,height_offset,ray_count,sky_color, andsky_intensity.renderer.get_probe_memory_report()returns diffuse and reflection probe counts, byte totals per subsystem, and a combinedtotal_bytes.Debug mode
50shows raw probe irradiance. Debug mode51shows probe blend weight.Debug mode
52shows raw reflection probe color. Debug mode53shows reflection probe blend weight.
Current boundary
TV5 now changes both diffuse indirect terrain lighting and the local specular fallback path.
Terrain specular still falls back to the global IBL cubemap outside reflection probe coverage.
The current baker is heightfield-analytical and terrain-only; it does not perform scene cubemap capture.
Example and tests
Example:
python examples/terrain_tv5_probe_lighting_demo.pyWater-focused reflection-probe demo:
python examples/terrain_tv24_reflection_probe_demo.pyAPI and behavior tests:
tests/test_terrain_probes.pyReal-DEM demo notes:
docs/examples/reflection_probe_demo.mdDetailed design/spec:
docs/superpowers/specs/2026-03-21-tv5-local-probe-lighting-design.md
The bundled demo writes six outputs:
probes disabled
probes enabled
probe irradiance debug
probe weight debug
reflection probe color debug
side-by-side comparison