Pylon Grid stands the song's object on its pylons
The scene already had the depth axis the solid wants — near rows large, far rows small, converging on the track's horizon — which made the flat crown the one element in it drawn without perspective: a sticker facing the viewer on top of a receding structure. Each crown is now marched, and each pylon turns its own at its own angle, so a single field shows the form from a dozen sides at once. 12/12 on the gate, 7ms/frame at 4K against a 60ms ceiling. A hundred and sixty instances stay affordable on the two guards MIGRATION.md now documents, and here first-wins is the correct occlusion as well as the cheap one, because the rows are already walked near to far. IT MEASURES SLIGHTLY WORSE and the scene's header says so: 0.141 to 0.134 over 8 songs x 8 seeds, nearly all of it layout (0.156 to 0.126). Two candidate causes were tested and both came back flat — keeping the far rows stamped scored 0.132, and running the lit surface through inkPattern scored 0.132 here and moved Effigy by 0.0009. It is the solid itself: a body always fills its own silhouette, where a stamped cast form paints anywhere between an outline and a disc depending on whether the identity is hollow, and that swing was worth three hundredths of layout variety. Kept because the score does not measure what was wrong. A crown that ignores the perspective of the field it stands in is a defect no coverage variance reports, and the header records the number and the two-line revert for whoever disagrees. The inkPattern experiment is reverted rather than left in as a plausible-looking no-op, with its measurements written where the next person will look for them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0a89676cc8
commit
61e0c66f61
@ -955,6 +955,13 @@ vec3 castLit(vec3 n, vec3 rd) {
|
|||||||
vec3 col = mix(pal(1) * 0.22, pal(2), diff);
|
vec3 col = mix(pal(1) * 0.22, pal(2), diff);
|
||||||
col += pal(0) * fill;
|
col += pal(0) * fill;
|
||||||
col += pal(3) * rim * 0.55;
|
col += pal(3) * rim * 0.55;
|
||||||
|
|
||||||
|
// Tried and reverted: modulating this by inkPattern, on the theory that a
|
||||||
|
// lit solid is the one thing in the video ignoring the track's FILL. It
|
||||||
|
// reads well and measures nothing — Pylon Grid 0.1324 to 0.1322, Effigy
|
||||||
|
// 0.2382 to 0.2373, both inside the last digit that means anything. The
|
||||||
|
// fill is already carried by the outline every solid scene draws beside the
|
||||||
|
// body, and by inkValue below.
|
||||||
return inkValue(col);
|
return inkValue(col);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,8 +1,32 @@
|
|||||||
// Structural family: a field of standing pylons receding to the track's
|
// Structural family: a field of standing pylons receding to the track's
|
||||||
// horizon. The columns converge on a vanishing point, giving real perspective
|
// horizon. The columns converge on a vanishing point, giving real perspective
|
||||||
// depth, and each column carries a crown in the signature form so a hexagonal
|
// depth, and each column carries the song's own object on top, so a hexagonal
|
||||||
// track grows hexagonal pylons. The beat walks a pulse of light down the rows
|
// track grows hexagonal pylons. The beat walks a pulse of light down the rows
|
||||||
// rather than flashing the whole frame.
|
// rather than flashing the whole frame.
|
||||||
|
//
|
||||||
|
// The crowns are SOLID. This scene already had the one thing the 3D cast needs
|
||||||
|
// and most scenes lack — a real depth axis, with near rows large and far rows
|
||||||
|
// small — so a flat crown was the only part of it drawn without perspective: a
|
||||||
|
// sticker facing the viewer on top of a receding structure. Marching them puts
|
||||||
|
// the object in the same space as the field it stands in, and because each
|
||||||
|
// pylon turns its own crown at its own angle, one field shows the song's form
|
||||||
|
// from a dozen sides at once. See castSolid.
|
||||||
|
//
|
||||||
|
// IT MEASURES SLIGHTLY WORSE, and that is worth writing down rather than
|
||||||
|
// discovering again. Over 8 songs x 8 seeds the flat version scored 0.141 and
|
||||||
|
// this one scores 0.134, almost all of it in the LAYOUT block (0.156 to 0.126).
|
||||||
|
// The cause is not resolution, and not the ink: two candidate fixes were tried
|
||||||
|
// and both measured flat — a size threshold keeping the far rows stamped
|
||||||
|
// (0.132) and running the lit surface through inkPattern (0.132). It is the
|
||||||
|
// solid itself. A body always fills its own silhouette, where a stamped cast
|
||||||
|
// form paints anywhere between an outline and a disc depending on whether the
|
||||||
|
// song's identity is hollow or has an outline-only fill, and that swing was
|
||||||
|
// worth three hundredths of layout variety.
|
||||||
|
//
|
||||||
|
// Kept anyway, because the variety score does not measure the thing that was
|
||||||
|
// wrong: a flat crown on a receding pylon is the one element in this scene that
|
||||||
|
// does not obey its own perspective, and no amount of coverage variance fixes
|
||||||
|
// that. Reverting is a two-line change if the number matters more.
|
||||||
|
|
||||||
export const pylonGrid = {
|
export const pylonGrid = {
|
||||||
name: 'Pylon Grid',
|
name: 'Pylon Grid',
|
||||||
@ -13,7 +37,7 @@ export const pylonGrid = {
|
|||||||
// Personality: see look/Personality.js.
|
// Personality: see look/Personality.js.
|
||||||
// Takes the track's surface grain, but lightly — this is drawn, not filmed.
|
// Takes the track's surface grain, but lightly — this is drawn, not filmed.
|
||||||
texture: 0.4,
|
texture: 0.4,
|
||||||
consumes: ['cast', 'ink'],
|
consumes: ['form', 'ink'],
|
||||||
traits: ['shape', 'space', 'style'],
|
traits: ['shape', 'space', 'style'],
|
||||||
|
|
||||||
params: {
|
params: {
|
||||||
@ -45,6 +69,11 @@ vec4 scene(vec2 uv, vec2 p) {
|
|||||||
float hy = sigHorizonY();
|
float hy = sigHorizonY();
|
||||||
vec3 col = pal(0) * 0.05;
|
vec3 col = pal(0) * 0.05;
|
||||||
|
|
||||||
|
// Whether a crown already owns this pixel. Rows are walked near to far, so
|
||||||
|
// first-wins is the correct occlusion here rather than merely the cheap one
|
||||||
|
// — and it bounds a hundred and sixty instances to about one march.
|
||||||
|
float painted = 0.0;
|
||||||
|
|
||||||
for (int r = 0; r < 10; r++) {
|
for (int r = 0; r < 10; r++) {
|
||||||
if (float(r) >= u_rows) break;
|
if (float(r) >= u_rows) break;
|
||||||
float fr = float(r);
|
float fr = float(r);
|
||||||
@ -72,10 +101,29 @@ vec4 scene(vec2 uv, vec2 p) {
|
|||||||
float w = 0.02 * scale + 0.006;
|
float w = 0.02 * scale + 0.006;
|
||||||
col += pal(int(mod(fc, 4.0))) * strut(p, cx, y0, yTop, w) * inten;
|
col += pal(int(mod(fc, 4.0))) * strut(p, cx, y0, yTop, w) * inten;
|
||||||
|
|
||||||
// Crown stamped in the track's signature form.
|
// The song's object, standing on the pylon.
|
||||||
vec2 crown = vec2(cx, yTop);
|
vec2 crown = vec2(cx, yTop);
|
||||||
float size = (0.06 + 0.2 * scale) * (1.0 + u_beat * 0.4);
|
float size = (0.06 + 0.2 * scale) * (1.0 + u_beat * 0.4);
|
||||||
col += pal(3) * castForm(p, crown, size) * inten * (0.6 + u_pulse);
|
vec2 local = (p - crown) / max(size, 1e-3);
|
||||||
|
|
||||||
|
if (dot(local, local) < 1.6 && painted < 0.5) {
|
||||||
|
// Each crown at its own angle, so the field is one form seen
|
||||||
|
// from many sides rather than one silhouette repeated. The turn
|
||||||
|
// is slow and per-pylon; the row term keeps a receding line of
|
||||||
|
// them from presenting the same profile all the way back.
|
||||||
|
mat3 turn = castTurn(t * 0.6 + fc * 0.9 + fr * 0.4, 0.2 + sin(t + fr) * 0.2);
|
||||||
|
vec3 n;
|
||||||
|
float hit = castSolid(local, turn, n);
|
||||||
|
if (hit > 0.0) {
|
||||||
|
painted = 1.0;
|
||||||
|
col = mix(col, castLit(n, vec3(0.0, 0.0, 1.0)) * inten * (0.6 + u_pulse), 0.92);
|
||||||
|
}
|
||||||
|
// Its outline in the track's line weight, which is what carries
|
||||||
|
// the far rows: at twelve percent scale a crown is a few pixels
|
||||||
|
// and the lit faces are gone before the edge is.
|
||||||
|
float d = castSDF3(turn * vec3(local, 0.0)) * size;
|
||||||
|
col += pal(3) * inkStroke(d) * inten * (0.5 + u_pulse);
|
||||||
|
}
|
||||||
col += pal(int(mod(fr, 4.0))) * exp(-dot(p - crown, p - crown) * 60.0) * u_pulse * depthShade;
|
col += pal(int(mod(fr, 4.0))) * exp(-dot(p - crown, p - crown) * 60.0) * u_pulse * depthShade;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user