luv

Workshop wiki

moppe-legacy.org

The Moppe legacy: lighting, post, and atmosphere worth transplanting

Moppe is evidence, a tuning library, and a legacy #C4XGYX

Moppe (~/src/moppe) is the predecessor engine: a C++/Metal terrain world with a complete cinematic renderer. It proves an ambitious end state on the actual development machines, preserves hundreds of tuned judgment calls, and shows what luv should improve: its answers are frozen in MSL and duplicated by convention, where luv can hold shared material meaning as live Lisp objects.

This page now stays a source-study and transplant inventory. The native backend motivation it originally contained has become executable luv work and moved, with its stable figure IDs, to the native Metal 4 backend. Read Moppe as #H7QK3M advises: observed mechanism, source claim, and luv's possible choice are different voices.

The post stack reveals what finished-looking means #8VA1EX

moppe/shaders/metal/post.metal supplies a concrete observed sequence:

  1. Auto-exposure averages wide HDR taps into a tiny CPU-read target and adapts one exposure scalar. Bloom sees the exposed scene.
  2. Bloom uses a soft-knee bright pass and quarter-resolution chain; a smoothstep (0.85, 1.35, luma) threshold and five-sample linear-filter trick evaluate the nine-tap Gaussian cheaply.
  3. Lens character adds edge-gated chromatic fringe, veil, anamorphic streak, and sun ghosts modulated by visibility.
  4. ACES tonemap converts the linear scene, followed by sRGB encoding.
  5. Color grade applies warm print-film CDL, split tone, vibrance, grain, and vignette.
  6. EDR output re-linearizes and permits true highlights above diffuse white within current display headroom.

The sequence matters more than any individual effect: exposure and tone mapping establish the medium in which bloom and grade make sense. #SKHDR already follows that order. Moppe's grade is especially attractive because it is cheap, separable, and made of constants which can become live uniforms or hot-redefined material methods.

Sun shafts are the highest-glamour transplant #BAP0QU

Moppe's shafts_gather_fragment marches view rays at half resolution through the existing shadow map, jitters them with interleaved-gradient noise, stops at scene depth, and weights lit spans by a forward Henyey-Greenstein lobe with g = 0.60. A separate pass filters and adds the result.

Luvcraft already owns both inputs: a stored shadow map (#2WX9PW) and offscreen scene depth. The effect needs no new world representation. It does need the linear-HDR target (#WLHDRB) so gathered light adds in meaningful units.

common.h is a library of judgment calls #094ZB1

moppe/shaders/metal/common.h is valuable less for novel algorithms than for tuning worth testing:

The strongest argument for re-expressing these in luv is duplication. The daylight / golden pair is recomputed independently in several shaders. In luv it can be one shader abstraction (#DXYHT4) reused with shared meaning and one live redefinition point.

Sky, temporal reconstruction, and mesh shaders bound the proof #KK6M0T

Three larger observations describe capabilities rather than immediate ports:

These are forcing examples, not reasons to import Moppe's renderer wholesale. The post stack is largely backend-neutral fullscreen work, while mesh stages should enter luv's shader language only when a concrete native pipeline makes their types and interfaces precise.

DONE Transplant the post stack onto the HDR path #VG8TGG

Intent: when #WLHDRB lands the linear-HDR scene target, extend it past tone map and restrained bloom toward Moppe's observed order: exposure, ACES, and a small live grade. Treat sun shafts (#BAP0QU) as the first post effect after bloom because both inputs already exist.

Observed: luvcraft's presentation stage now composes in linear light in Moppe's order --- exposure, bloom, shafts, the same Narkowicz ACES fit, and a vignette --- with every parameter a live special rather than a compiled constant (#IC14P3). The bright pass took Moppe's soft-knee threshold and its five-linear-sample gaussian directly; the difference is that each stage is a CLOS shader role rather than a named Metal fragment function, so a redefined method rebuilds its pipeline at the next frame boundary.

Two of Moppe's stages were deliberately not transplanted. The chromatic fringe, ghosts, grain, and CDL-style grade belong to a photographic look which this block world has not asked for, and none of them would be evidence of anything. Auto-exposure needs the readback probe and adaptation loop, which is its own piece of work; the sky profile's static exposure is enough while the frame has no wildly varying luminance.

The shafts departed further: they sweep the blurred bright image toward the sun's screen position rather than marching the shadow map, so the "frame-time cost for the half-resolution shaft march" this mark asked to measure has no subject yet. #94AUTK carries the marched version as the thing to compare against.

IDEA March the shadow map for shafts and compare against the screen sweep #94AUTK

Intent: #VG8TGG shipped the cheap radial sweep because terrain which occludes the sun is already dark in the bright image. #BAP0QU's marched version is strictly better informed: it knows about occluders which are off screen or behind the camera, and it produces beams in air the bright image says nothing about. Whether that is visible enough to pay for is a measurement, not an argument.

Evidence to gather:

Done when: one of the two is chosen with a capture pair and a frame-time pair recorded here, or both are kept with a stated reason for choosing between them at runtime.