Shader graph: Abs node, the distance from 0 per channel
game-maker / suite (push) Failing after 8m10s
game-maker / suite (push) Failing after 8m10s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
a399795772
commit
28c0789b19
4 files changed
+59
-1
No files matched your search
@@ -37,7 +37,7 @@ npm run build # writes dist/ and regenerates index.html; the folder is wh
|
||||
The browser suite and the three example games need a machine with a GPU:
|
||||
|
||||
```bash
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 762 checks (GM_STEPS=20 for one step)
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # the editor, 763 checks (GM_STEPS=20 for one step)
|
||||
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs
|
||||
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs
|
||||
node tools/seed-actor.mjs && node tools/smoke-actor.mjs
|
||||
|
||||
@@ -341,6 +341,12 @@ export const ShaderFract = unary(
|
||||
'fract',
|
||||
'The part after the decimal point: 2.75 becomes 0.75. A rising value becomes a sawtooth from 0 to 1.',
|
||||
);
|
||||
export const ShaderAbs = unary(
|
||||
'ShaderAbs',
|
||||
'Abs',
|
||||
'abs',
|
||||
'The distance from 0, sign dropped: -0.3 becomes 0.3. A value crossing 0 becomes a V. Per channel for colours.',
|
||||
);
|
||||
|
||||
export const ShaderStep: ShaderNodeDef = {
|
||||
type: 'ShaderStep',
|
||||
@@ -392,6 +398,7 @@ export const SHADER_NODES: readonly ShaderNodeDef[] = [
|
||||
ShaderSin,
|
||||
ShaderFloor,
|
||||
ShaderFract,
|
||||
ShaderAbs,
|
||||
ShaderStep,
|
||||
ShaderPow,
|
||||
];
|
||||
|
||||
@@ -470,6 +470,27 @@ describe('compileShader', () => {
|
||||
expect(fragment).toMatch(/float n\d+_result = pow\(max\(n\d+_u, 0\.0\), 2\.0\);/);
|
||||
expect(fragment).toMatch(/vec3 n\d+_result = pow\(max\(n\d+_color, 0\.0\), vec3\(2\.2\)\);/);
|
||||
});
|
||||
|
||||
it('writes Abs as the GLSL call, per channel for a colour', () => {
|
||||
const f = makeProject();
|
||||
const s = shaderEditor(f, 'Fold');
|
||||
const uv = s.add(SHADER_UV);
|
||||
const centred = s.add('ShaderSubtract', { b: 0.5 });
|
||||
const folded = s.add('ShaderAbs');
|
||||
const tint = s.add('ShaderColor', { value: 0xff8000 });
|
||||
const magnitude = s.add('ShaderAbs');
|
||||
const output = s.add(SHADER_OUTPUT);
|
||||
s.link(uv, 'u', centred, 'a');
|
||||
s.link(centred, 'result', folded, 'value');
|
||||
s.link(folded, 'result', output, 'alpha');
|
||||
s.link(tint, 'color', magnitude, 'value');
|
||||
s.link(magnitude, 'result', output, 'color');
|
||||
const build = compileShader(s.asset().graph);
|
||||
expect(build.problems).toEqual({});
|
||||
const { fragment } = build.compiled!;
|
||||
expect(fragment).toMatch(/float n\d+_result = abs\(n\d+_result\);/);
|
||||
expect(fragment).toMatch(/vec3 n\d+_result = abs\(n\d+_color\);/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a sprite wearing a shader', () => {
|
||||
|
||||
@@ -127,6 +127,9 @@ export async function shader(t) {
|
||||
// 28c. A Property node: its name is the row a sprite shows; a bad name is a problem on the node.
|
||||
await click(canvas.x + 80, canvas.y + 320, 'right');
|
||||
await sleep(300);
|
||||
// Property is the twelfth entry, below the palette's scroll mask: search it into view first.
|
||||
await typeText('Property');
|
||||
await sleep(150);
|
||||
await clickLast('Property');
|
||||
await sleep(300);
|
||||
const propertyNode = (await madeNodes()).find((n) => n.type === 'ShaderProperty');
|
||||
@@ -503,6 +506,33 @@ export async function shader(t) {
|
||||
{ rootNear, rootFar },
|
||||
);
|
||||
|
||||
// 28k-iii. Abs folds u around 0.5 into a V: |u - 0.5| is below 0.25 only in the middle half.
|
||||
await redOrBlue(
|
||||
[
|
||||
node('uv', 'ShaderUV'),
|
||||
node('centred', 'ShaderSubtract', { b: 0.5 }, 260, 0),
|
||||
node('fold', 'ShaderAbs', {}, 260, 120),
|
||||
node('cut', 'ShaderStep', { edge: 0.25 }, 260, 240),
|
||||
],
|
||||
[
|
||||
edge('uv', 'u', 'centred', 'a'),
|
||||
edge('centred', 'result', 'fold', 'value'),
|
||||
edge('fold', 'result', 'cut', 'value'),
|
||||
edge('cut', 'result', 'mix', 't'),
|
||||
],
|
||||
);
|
||||
await sleep(400);
|
||||
const foldLeft = await pixel(-0.4, -0.3);
|
||||
const foldMiddle = await pixel(0, -0.3);
|
||||
const foldRight = await pixel(0.4, -0.3);
|
||||
check(
|
||||
'Abs folds the cut into a V: red in the middle, blue at both edges',
|
||||
colourDistance(foldMiddle, '#ff0000') < 6 &&
|
||||
colourDistance(foldLeft, '#0000ff') < 6 &&
|
||||
colourDistance(foldRight, '#0000ff') < 6,
|
||||
{ foldLeft, foldMiddle, foldRight },
|
||||
);
|
||||
|
||||
// 28l. Sample texture reads the picture where the graph says. On a pasted two-colour picture:
|
||||
// flipped u swaps the halves; u + 0.5 past the border shows the Output's Edge – Repeat continues
|
||||
// with the far half, Mirror with the near one.
|
||||
|
||||
Reference in new issue
Block a user