Pylon Grid stands on the chorus instead of on a strut
The legs were the last thing in this scene it had invented for itself: a fixed-width vertical capsule, the same object in every video, with only the palette separating one track's structure from another's. Against migrated crowns they read as scaffolding left up around a finished building — and structure is half this frame, so half of it was still saying what the SCENE is rather than what the song is. A leg is now a stack of the song's chorus. How many members make up a column is the song's element size deciding it — a track of few huge forms stands on three, a track of many small ones on a ladder of nine — and how wide the column is comes from the chorus's own proportions. Each member turns at its own angle, so a column is one form seen many ways rather than one form printed nine times. That makes `staging` a third declared artifact, which the lint caught before the gate had to. Measured on the crop that contains the change, since the frame-level score cannot see it: over six identities the bottom third of the frame moves 13.4/255 with the old strut and 22.2/255 with the chorus stacked. The whole-frame variety score goes 0.1322 to 0.1348, and the header now explains why the two disagree and why both are right — the crowns dominate a descriptor averaged over the whole image. Cost is unchanged in practice: 7.7ms/frame at 4K, 12.4ms with every param at the top of its range, against a 60ms ceiling. The column's bounding box is two comparisons for a pixel outside it, which with a hundred and sixty pylons is most of the budget. The crown is resolved before the leg now. Resolved the other way round, the first-wins rule let the column paint over the object standing on it and every subject was cut off at the waist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
61e0c66f61
commit
7d151be6e1
@ -4,6 +4,14 @@
|
|||||||
// 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.
|
||||||
//
|
//
|
||||||
|
// Nothing here is the scene's own invention any more. The crown is the song's
|
||||||
|
// protagonist and the LEG is a stack of its chorus: a column of bodies holding
|
||||||
|
// the subject up, rather than the thin fixed-width strut this drew for years.
|
||||||
|
// That strut was the same object in every video — a scene that has migrated its
|
||||||
|
// subject and kept its structure is still telling you what IT is, in the half of
|
||||||
|
// the frame that is structure, and next to a marched crown it read as scaffolding
|
||||||
|
// left up around a finished building.
|
||||||
|
//
|
||||||
// The crowns are SOLID. This scene already had the one thing the 3D cast needs
|
// 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
|
// 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
|
// small — so a flat crown was the only part of it drawn without perspective: a
|
||||||
@ -12,32 +20,40 @@
|
|||||||
// pylon turns its own crown at its own angle, one field shows the song's form
|
// pylon turns its own crown at its own angle, one field shows the song's form
|
||||||
// from a dozen sides at once. See castSolid.
|
// from a dozen sides at once. See castSolid.
|
||||||
//
|
//
|
||||||
// IT MEASURES SLIGHTLY WORSE, and that is worth writing down rather than
|
// WHAT THE NUMBERS SAY, since two of them disagree and both are right.
|
||||||
// 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
|
// Crop to the bottom third of the frame — the near rows, where the columns are
|
||||||
// wrong: a flat crown on a receding pylon is the one element in this scene that
|
// tall and the crowns are not — and measure how far apart six identities are:
|
||||||
// does not obey its own perspective, and no amount of coverage variance fixes
|
// 13.4/255 with the old strut, 22.2/255 with the chorus stacked. That is the
|
||||||
// that. Reverting is a two-line change if the number matters more.
|
// complaint answered. The strut was a fixed width and a fixed shape, so the only
|
||||||
|
// thing separating one video's structure from another's was the palette.
|
||||||
|
//
|
||||||
|
// The whole-frame variety score barely moves for it: 0.1322 to 0.1348 over
|
||||||
|
// 8 songs x 8 seeds. That is honest rather than disappointing — the crowns
|
||||||
|
// already dominate a frame-level descriptor, and a measurement averaged over the
|
||||||
|
// whole image cannot see a change confined to the lower third. It is the reason
|
||||||
|
// the crop above exists.
|
||||||
|
//
|
||||||
|
// The frame score is also still under the flat version's 0.141, and the cause is
|
||||||
|
// known: 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. Two
|
||||||
|
// candidate fixes were tried and both measured flat — keeping the far rows
|
||||||
|
// stamped (0.132), and running the lit surface through inkPattern (0.132 here,
|
||||||
|
// and 0.0009 on Effigy). It is the solid itself, and the trade is deliberate:
|
||||||
|
// the score does not measure a crown that ignores the perspective of the field
|
||||||
|
// it stands in, or a leg that is the same object in every video.
|
||||||
|
|
||||||
export const pylonGrid = {
|
export const pylonGrid = {
|
||||||
name: 'Pylon Grid',
|
name: 'Pylon Grid',
|
||||||
family: 'structural',
|
family: 'structural',
|
||||||
kind: 'fragment',
|
kind: 'fragment',
|
||||||
// Paints 27% of the frame — see checks/phase12 coverage.
|
// Paints 25% of the frame — see checks/phase12 coverage.
|
||||||
surface: 'composable',
|
surface: 'composable',
|
||||||
// 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: ['form', 'ink'],
|
consumes: ['form', 'ink', 'staging'],
|
||||||
traits: ['shape', 'space', 'style'],
|
traits: ['shape', 'space', 'style'],
|
||||||
|
|
||||||
params: {
|
params: {
|
||||||
@ -56,14 +72,6 @@ export const pylonGrid = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
shader: `
|
shader: `
|
||||||
// Distance to a thin vertical strut from (cx, y0) up to (cx, y1).
|
|
||||||
float strut(vec2 p, float cx, float y0, float y1, float w) {
|
|
||||||
float xd = abs(p.x - cx);
|
|
||||||
float yd = max(max(y0 - p.y, p.y - y1), 0.0);
|
|
||||||
float d = sqrt(xd * xd + yd * yd);
|
|
||||||
return smoothstep(w + 0.004, w - 0.004, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 scene(vec2 uv, vec2 p) {
|
vec4 scene(vec2 uv, vec2 p) {
|
||||||
float t = u_time * u_speed + u_seed;
|
float t = u_time * u_speed + u_seed;
|
||||||
float hy = sigHorizonY();
|
float hy = sigHorizonY();
|
||||||
@ -98,9 +106,11 @@ vec4 scene(vec2 uv, vec2 p) {
|
|||||||
float walk = sat(1.0 - abs(fr - mod(u_beatPhase * 6.0 + t * 0.4, u_rows)));
|
float walk = sat(1.0 - abs(fr - mod(u_beatPhase * 6.0 + t * 0.4, u_rows)));
|
||||||
float inten = (0.35 + 0.65 * walk) * depthShade * (0.7 + 0.3 * u_beat);
|
float inten = (0.35 + 0.65 * walk) * depthShade * (0.7 + 0.3 * u_beat);
|
||||||
|
|
||||||
float w = 0.02 * scale + 0.006;
|
// The crown is resolved BEFORE the leg, because the two overlap
|
||||||
col += pal(int(mod(fc, 4.0))) * strut(p, cx, y0, yTop, w) * inten;
|
// where the object sits on the column and the crown has to win it —
|
||||||
|
// resolved the other way round, every subject is cut off at the
|
||||||
|
// waist by the thing holding it up.
|
||||||
|
//
|
||||||
// The song's object, standing on the pylon.
|
// 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);
|
||||||
@ -125,6 +135,38 @@ vec4 scene(vec2 uv, vec2 p) {
|
|||||||
col += pal(3) * inkStroke(d) * inten * (0.5 + u_pulse);
|
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;
|
||||||
|
|
||||||
|
// THE LEG: the chorus, stacked. How many members make up a column
|
||||||
|
// is the song's element size deciding it — a track built of a few
|
||||||
|
// huge forms stands on three of them, a track of many small ones on
|
||||||
|
// a ladder of nine — and how WIDE the column is comes from the
|
||||||
|
// chorus's own proportions, which is why no two songs get the same
|
||||||
|
// pylon. See Identity.js: this is what the chorus solid is for.
|
||||||
|
float segs = clamp(floor(2.0 + 3.6 / max(stageScale(), 0.3)), 2.0, 9.0);
|
||||||
|
float member = max(h / (segs * 2.0), 1e-3);
|
||||||
|
|
||||||
|
// The bounding test is the column's own box, so a pixel outside it
|
||||||
|
// costs two comparisons rather than a march. With a hundred and
|
||||||
|
// sixty pylons on screen that test is most of the scene's budget.
|
||||||
|
if (abs(p.x - cx) < member * 1.3 && p.y > y0 - member * 0.3
|
||||||
|
&& p.y < yTop + member * 0.3 && painted < 0.5) {
|
||||||
|
float rung = floor((p.y - y0) / (member * 2.0));
|
||||||
|
float centreY = y0 + (rung + 0.5) * member * 2.0;
|
||||||
|
vec2 legLocal = vec2(p.x - cx, p.y - centreY) / member;
|
||||||
|
|
||||||
|
// Every member at its own angle, so a column is a stack of one
|
||||||
|
// form seen many ways rather than one form printed nine times.
|
||||||
|
mat3 legTurn = castTurn(t * 0.35 + rung * 1.1 + fc * 0.5, rung * 0.5);
|
||||||
|
vec3 ln;
|
||||||
|
float legHit = castChorusSolid(legLocal, legTurn, ln);
|
||||||
|
if (legHit > 0.0) {
|
||||||
|
painted = 1.0;
|
||||||
|
col = mix(col, castLit(ln, vec3(0.0, 0.0, 1.0))
|
||||||
|
* mix(inten, 1.0, 0.25) * pal(int(mod(fc, 4.0))) * 1.6, 0.9);
|
||||||
|
}
|
||||||
|
col += pal(int(mod(fc, 4.0)))
|
||||||
|
* inkStroke(castChorus3(legTurn * vec3(legLocal, 0.0)) * member) * inten * 0.8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user