Expand description
Warp mesh: a per-vertex UV grid that resamples the previous frame (ADR-0113).
§What it generalizes
ADR-0048 gave the engine one affine transform through which an accumulation
reads its own past: a single zoom, rotation and translation applied
identically to every texel. This scene is that transform per vertex. The
frame is covered by a grid of cells; each of its vertices carries its own
zoom/rot/cx/cy/dx/dy/ sx/sy/warp, and the rasterizer
interpolates between them — so the past can spiral in one corner and drift in
another, which no single affine can express.
Those nine outputs come from a preset’s [per_vertex] table, whose bindings
are evaluated once per vertex per frame with x, y, rad and ang bound
to that vertex’s own position. A preset that declares no such table gets the
scalar params of the same names applied everywhere, which is exactly ADR-0048’s
single shared transform — so the idiom degrades to the one it generalizes.
§The grid is a resolution, not a shape
ADR-0037, and this is the most likely place in the engine to get it wrong,
because here the grid is user-visible: a preset names [mesh] x and [mesh] y, and they are quantized and clamped to a tier capacity. Every
screen-destined coordinate here takes its aspect from the render target — the
rad/ang the per-vertex program reads (computed in vertex_position), and
the isotropic space the source-uv transform works in (computed in the vertex
shader from a uniform the CPU fills with the target’s aspect).
meshx/meshy appear in neither. A f32 aspect derived from the mesh size
would be the bug.
§Three passes
- warp — the mesh is drawn into the write half of a ping-pong field,
sampling the read half through each vertex’s source uv and scaling it by
decay^dt. This is the only pass that is not fullscreen. - deposit — a fullscreen pass adding this frame’s light onto the warped past: a palette-coloured gaussian ring with optional angular arms. It runs after the warp, so the light it lays down is “now” and is warped from the next frame onward.
- present — a fullscreen pass compositing the field over the backdrop,
premultiplied (ADR-0026), scaled by
brightnessandocclude.
All three rates are per second (ADR-0019): decay, zoom, sx, sy are
factors per second and rot/dx/dy/warp/deposit are amounts per second,
so the look is identical at 60 Hz and 144 Hz.
GPU resources are built lazily on first render, for the reason
reaction_diffusion.rs documents: a capture that never activates this scene
never builds this scene’s pipelines, so it cannot perturb another scene’s
render on the DX12 WARP software adapter (a WARP reading, unverified on
lavapipe as of 2026-10-06).
Modules§
- draw
- What MilkDrop draws between the warp and the composite (Plan 0100 Phase 4): the waveform, the custom waves and shapes, the two borders, and the motion-vector grid.
Structs§
- Warp
Mesh Scene - The warp mesh scene (ADR-0113).
Constants§
- COMPOSITE_
PARAMS - MilkDrop’s composite roster, in the order
COMPOSITE_PARAMSdeclares it — the six flags and one multiplier its format carries, reachable from a preset and written by a converted bundle’s per-frame program. - DEFAULT_
MESH - The grid a
[mesh]table’s absent keys mean. Coarse enough to be free on any machine and fine enough that arad-driven program reads as a curve rather than as facets. - MAX_
MESH - The largest grid any tier may name, in cells — the
.milkformat’s own ceiling (meshx <= 128,meshy <= 96), so a converted preset’s requested grid is always representable. - MAX_
SHAPE_ VERTICES - The most vertices the filled-shape buffer holds.
- MILKDROP_
SOFTNESS - The
softnesseverywarp_meshstroke is drawn at — the waveform, every custom wave, every shape outline, both borders and the motion grid, which all reach the line fragment through oneLineRenderer::draw_splitcall. - MIN_
MESH - The smallest grid a
[mesh]table may name, in cells. Below two the mesh is a single quad and the per-vertex program has no interior to interpolate. - PARAMS
- Parameter vocabulary — see
fragment_field::PARAMS. Keep in sync withset_parambelow. - PER_
VERTEX_ PARAMS - The nine outputs a
[per_vertex]table may bind, in the order this scene stores them. Keep in step withPER_VERTEX_DEFAULTSandWarpMeshScene::set_per_vertex.
Functions§
- clamp_
grid - Clamp a preset’s requested grid into what
tierwill carry. - vertex_
count - How many vertices a grid of
meshcells has. One more than the cell count on each axis — the fencepost the whole per-vertex path is sized by. - vertex_
position - The
(x, y, rad, ang)a vertex’s[per_vertex]bindings are evaluated against, for the vertex at columncol, rowrowof ameshgrid, on a render target of aspectaspect.