Shader graph: alpha input on Output, Texture alpha node (#70)
game-maker / suite (push) Successful in 7m55s
game-maker / suite (push) Successful in 7m55s
Output gains a number input `alpha`; unconnected it reads the texel's alpha, like `color` reads the texel. The epilogue premultiplies with the resolved alpha. New `Texture alpha` node exposes texel.a for maths. PortDef.inline=false keeps the alpha port without an inline field: every number port is inline by default, and a typed default of 0 would have made every shaded sprite invisible. The compiler's texel fallback is typed: colour ports get rgb, number ports get texel.a. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
b0c4b4ec5a
commit
3da0ef1be2
6 files changed
+125
-12
No files matched your search
+48
-1
@@ -276,7 +276,54 @@ export async function shader(t) {
|
||||
red,
|
||||
);
|
||||
|
||||
// 28h. Back to None: no filter at all, the plain colour returns bit for bit.
|
||||
// 28h. Alpha: Texture alpha times a Property into the Output's alpha blends the sprite with what
|
||||
// is behind it; at 1 the pixel is the one from before, byte for byte.
|
||||
await mutate(`
|
||||
const a = __gm.state.project.assets.find((x) => x.id === ${JSON.stringify(made.id)});
|
||||
const out = a.graph.nodes.find((n) => n.type === 'ShaderOutput');
|
||||
a.graph.nodes.push(
|
||||
{ id: 'sh-alpha', type: 'ShaderTextureAlpha', x: 0, y: 300, params: {} },
|
||||
{ id: 'sh-opacity', type: 'ShaderProperty', x: 0, y: 400, params: { name: 'opacity', default: 1, min: 0, max: 1 } },
|
||||
{ id: 'sh-fade', type: 'ShaderMultiply', x: 200, y: 350, params: {} });
|
||||
a.graph.edges.push(
|
||||
{ id: 'sh-fade-a', from: { node: 'sh-alpha', port: 'value' }, to: { node: 'sh-fade', port: 'a' } },
|
||||
{ id: 'sh-fade-b', from: { node: 'sh-opacity', port: 'value' }, to: { node: 'sh-fade', port: 'b' } },
|
||||
{ id: 'sh-fade-out', from: { node: 'sh-fade', port: 'result' }, to: { node: out.id, port: 'alpha' } });`);
|
||||
await sleep(400);
|
||||
const opaque = await centre();
|
||||
check(
|
||||
'an opacity property at its default 1 changes nothing',
|
||||
opaque === red,
|
||||
JSON.stringify({ red, opaque, info: await info() }),
|
||||
);
|
||||
await assetProps({ opacity: 0 });
|
||||
await sleep(300);
|
||||
const behind = await centre();
|
||||
check('opacity 0 shows what is behind the sprite', colourDistance(behind, red) > 60, { red, behind });
|
||||
await assetProps({ opacity: 0.5 });
|
||||
await sleep(300);
|
||||
const half = await centre();
|
||||
const channel = (hex, i) => parseInt(hex.slice(i, i + 2), 16);
|
||||
const expected =
|
||||
'#' +
|
||||
[1, 3, 5]
|
||||
.map((i) =>
|
||||
Math.round((channel(red, i) + channel(behind, i)) / 2)
|
||||
.toString(16)
|
||||
.padStart(2, '0'),
|
||||
)
|
||||
.join('');
|
||||
check('opacity 0.5 blends the sprite half with what is behind', colourDistance(half, expected) < 24, {
|
||||
red,
|
||||
behind,
|
||||
half,
|
||||
expected,
|
||||
});
|
||||
await assetProps({ opacity: 1 });
|
||||
await sleep(300);
|
||||
check('opacity back at 1 draws the pixel from before, byte for byte', (await centre()) === red);
|
||||
|
||||
// 28i. Back to None: no filter at all, the plain colour returns bit for bit.
|
||||
await assetProps({ shader: '' });
|
||||
await sleep(300);
|
||||
const back = await centre();
|
||||
|
||||
Reference in new issue
Block a user