Let a shader move the corners of the picture it wears (#79)
A shader could only say what colour a pixel has. Where the picture is drawn was fixed to the four corners of its rectangle, so nothing could wave, bend or wobble. - The new node Vertex output takes x and y, in pixels of the picture, and moves every corner of the wearer's grid by them. The UVs stay with the corners, so the picture bends along. - Subdivisions on that node says how fine the grid is: cells per axis, 1 to 64, 8 by default. 1 is the plain quad. A shader without the node keeps the quad every sprite shares. - A graph holds one Vertex output at most. UV, Time, Property, Number and the math nodes may feed it, and one node may feed both outputs. - Texture color, Texture alpha, Sample texture, Texture size and Color cannot feed it. The node says "Not available per corner" and the shader does not compile. - Sprites, texts and the preview in the shader tab wear the grid. A nine-slice sprite and particles draw as if the node were not there. - Picking, the selection frame, the size and colliders stay with the rectangle. A wearer with a Vertex output is never culled, as with Padding, and with Padding the grid covers the room around the picture too. - tools/perf-shaders.mjs takes GM_PERF_SUBDIVISIONS to measure a grid against the plain quad. Measured on stein2 (Intel HD 630), frames per second, one run per row: at 800 sprites 58 with a shader on the quad, 46 with 8 cells, 41 with 32. Up to 400 sprites a grid hardly shows. Every sprite holds its own grid. Tests: - Gate on melektaus-atx: 220 files, 3416 tests, CHECK EXIT 0. - 15 new unit tests for the compiler and the grid. - Four new e2e checks in modules 28 and 30: a fixed offset moves the picture, 8 cells bend only the lower half where 1 cell shears it all, Texture alpha is refused at the node, a text moves. - e2e 28,30 on melektaus-atx: 110 checks, all pass. - The e2e total of 1699 is counted (1695 + 4), the full suite did not run. - No counter-probe, no screenshot. Not looked at: the preview, Time in the browser, flipped sprites, Padding together with the grid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
963f8a152a
commit
4716726b6b
14 files changed
+586
-75
No files matched your search
@@ -29,7 +29,7 @@ import {
|
||||
} from '../../core/properties/particles';
|
||||
import { nextPropertyName, PROPERTY_NAME_PARAM, SHADER_PROPERTY } from '../../core/properties/shaders';
|
||||
import { nextParticlePropertyName, PARTICLE_NODES, PARTICLE_OUTPUT } from '../../core/particles/nodes';
|
||||
import { SHADER_NODES, SHADER_OUTPUT } from '../../core/shader/nodes';
|
||||
import { SHADER_NODES, SHADER_OUTPUT, SHADER_VERTEX_OUTPUT } from '../../core/shader/nodes';
|
||||
|
||||
/**
|
||||
* One row of the palette. `def` is the definition the node would actually have once placed, so the
|
||||
@@ -95,8 +95,9 @@ export function paletteEntries(project: Project, asset: GraphAsset): PaletteEntr
|
||||
return [{ id: State.type, hint: State.category, def: State, params }];
|
||||
}
|
||||
if (asset.type === 'shader') {
|
||||
const hasOutput = asset.graph.nodes.some((n) => n.type === SHADER_OUTPUT);
|
||||
return SHADER_NODES.filter((def) => def.type !== SHADER_OUTPUT || !hasOutput).map((def) => {
|
||||
const placed = new Set(asset.graph.nodes.map((n) => n.type));
|
||||
const once = [SHADER_OUTPUT, SHADER_VERTEX_OUTPUT];
|
||||
return SHADER_NODES.filter((def) => !once.includes(def.type) || !placed.has(def.type)).map((def) => {
|
||||
const params: PropertyBag =
|
||||
def.type === SHADER_PROPERTY ? { [PROPERTY_NAME_PARAM]: nextPropertyName(asset.graph) } : {};
|
||||
return { id: def.type, hint: def.category, def, params };
|
||||
|
||||
@@ -114,10 +114,11 @@ export class ShaderPreview extends Widget {
|
||||
);
|
||||
this.mesh.position.set(Math.round(this.w / 2), Math.round(this.h / 2));
|
||||
this.mesh.scale.set(w * zoom, h * zoom);
|
||||
syncQuadPadding(this.mesh, worn?.padding ?? 0, texture?.width ?? w, texture?.height ?? h);
|
||||
const counted = { w: texture?.width ?? w, h: texture?.height ?? h };
|
||||
syncQuadPadding(this.mesh, worn?.padding ?? 0, counted.w, counted.h, worn?.vertex?.subdivisions ?? 1);
|
||||
this.mesh.texture = texture ?? Texture.WHITE;
|
||||
this.mesh.tint = picture?.tint ?? 0xffffff;
|
||||
syncShader(this.mesh, { ...this.values, [SHADER_KEY]: this.shader.id }, source);
|
||||
syncShader(this.mesh, { ...this.values, [SHADER_KEY]: this.shader.id }, source, counted);
|
||||
}
|
||||
|
||||
override destroy(): void {
|
||||
|
||||
Reference in new issue
Block a user