Shader graph: alpha input on Output, Texture alpha node (#70)
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:
rootandClaude Fable 5.1 committed 2026-09-13 11:51:59 +02:00
1 parent b0c4b4ec5a
commit 3da0ef1be2
6 files changed
+125 -12

No files matched your search

+10 -4
View File
@@ -8,6 +8,7 @@ import {
floatLiteral,
isShaderNodeDef,
SHADER_OUTPUT,
TEXEL_ALPHA,
TEXEL_COLOR,
uniformName,
vec3Literal,
@@ -89,7 +90,10 @@ export function compileShader(graph: Graph): ShaderBuild {
return outputs;
};
/** What feeds an input: the edge's source, the typed-in value, or – with nothing to type – the texel. */
/**
* What feeds an input: the edge's source, the typed-in value, or – with nothing to type – the
* texel: its colour for a colour port, its alpha for a number port.
*/
const input = (node: GraphNode, port: PortDef): Expr | null => {
const edge = edgesInto(graph, node.id, port.key)[0];
if (edge) {
@@ -103,7 +107,7 @@ export function compileShader(graph: Graph): ShaderBuild {
if (port.field?.kind === 'color')
return { code: vec3Literal(colorOf(typed ?? 0xffffff, 0xffffff)), type: 'vec3' };
if (port.field) return { code: floatLiteral(Number(typed ?? 0)), type: 'float' };
return TEXEL_COLOR;
return port.type === 'number' ? TEXEL_ALPHA : TEXEL_COLOR;
};
const conform = (node: GraphNode, port: PortDef, expr: Expr): Expr | null => {
@@ -119,9 +123,10 @@ export function compileShader(graph: Graph): ShaderBuild {
if (!output) return { compiled: null, problems, reason: 'No Output node' };
const outputDef = nodeDef(SHADER_OUTPUT)!;
const color = input(output, outputDef.inputs[0]!);
const alpha = input(output, outputDef.inputs[1]!);
const first = graph.nodes.find((n) => n.id in problems);
if (first || !color)
if (first || !color || !alpha)
return { compiled: null, problems, reason: first ? problems[first.id]! : 'Cannot compile' };
const uniforms = shaderParamDefs(graph).map((row) => ({ name: row.key, default: row.default }));
@@ -135,7 +140,8 @@ export function compileShader(graph: Graph): ShaderBuild {
' vec4 texel = texture(uTexture, vTextureCoord);',
` vec3 ${TEXEL_COLOR.code} = texel.a > 0.0 ? texel.rgb / texel.a : texel.rgb;`,
...lines.map((line) => ` ${line}`),
` finalColor = vec4(clamp(${color.code}, 0.0, 1.0) * texel.a, texel.a);`,
` float alpha = clamp(${alpha.code}, 0.0, 1.0);`,
` finalColor = vec4(clamp(${color.code}, 0.0, 1.0) * alpha, alpha);`,
'}',
'',
].join('\n');