A square root is one node everywhere else, so the shader graph gets its own (#92)
game-maker / suite (push) Successful in 10m29s
game-maker / suite (push) Successful in 10m29s
`Sqrt` already exists in the behavior graph (`data/Sqrt.ts`) and in particles (`ParticleSqrt`); the shader was the only graph without it. `Pow` with exponent 0.5 does the same job, so this is convenience, not a missing capability -- a radial falloff no longer needs a node whose purpose has to be read off its parameter. Like `Pow` it cannot go through `unary()`: GLSL leaves `sqrt` undefined below 0, so the value is held there with `max(value, 0.0)`. That form takes a float second argument for a `vec3` too, so unlike `pow` the exponent broadcast has no counterpart here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
80dd82349d
commit
2637feb715
2 files changed
+35
No files matched your search
@@ -383,6 +383,21 @@ export const ShaderPow: ShaderNodeDef = {
|
||||
},
|
||||
};
|
||||
|
||||
/** GLSL leaves `sqrt` undefined below 0, so the value is held at 0 there. */
|
||||
export const ShaderSqrt: ShaderNodeDef = {
|
||||
type: 'ShaderSqrt',
|
||||
label: 'Sqrt',
|
||||
category: 'shader',
|
||||
description:
|
||||
'The square root: 0.25 becomes 0.5, 4 becomes 2. Below 0 the value counts as 0. Per channel for colours.',
|
||||
inputs: [anyIn('value', 0)],
|
||||
outputs: [anyOut('result')],
|
||||
params: [],
|
||||
emit: ({ value }) => ({
|
||||
result: { code: `sqrt(max(${value!.code}, 0.0))`, type: value!.type },
|
||||
}),
|
||||
};
|
||||
|
||||
/** Every node a shader graph offers. Registered by `graph/nodes`, offered by no behavior palette. */
|
||||
export const SHADER_NODES: readonly ShaderNodeDef[] = [
|
||||
ShaderTextureColor,
|
||||
@@ -407,6 +422,7 @@ export const SHADER_NODES: readonly ShaderNodeDef[] = [
|
||||
ShaderAbs,
|
||||
ShaderStep,
|
||||
ShaderPow,
|
||||
ShaderSqrt,
|
||||
];
|
||||
|
||||
/** A GLSL float literal: always with a decimal point, so `1` does not become an int. */
|
||||
|
||||
@@ -487,6 +487,25 @@ describe('compileShader', () => {
|
||||
expect(fragment).toMatch(/vec3 n\d+_result = pow\(max\(n\d+_color, 0\.0\), vec3\(2\.2\)\);/);
|
||||
});
|
||||
|
||||
it('writes Sqrt as the GLSL call with the value held at 0, per channel for a colour', () => {
|
||||
const f = makeProject();
|
||||
const s = shaderEditor(f, 'Root');
|
||||
const uv = s.add(SHADER_UV);
|
||||
const root = s.add('ShaderSqrt');
|
||||
const tint = s.add('ShaderColor', { value: 0xff8000 });
|
||||
const rolled = s.add('ShaderSqrt');
|
||||
const output = s.add(SHADER_OUTPUT);
|
||||
s.link(uv, 'u', root, 'value');
|
||||
s.link(root, 'result', output, 'alpha');
|
||||
s.link(tint, 'color', rolled, 'value');
|
||||
s.link(rolled, 'result', output, 'color');
|
||||
const build = compileShader(s.asset().graph);
|
||||
expect(build.problems).toEqual({});
|
||||
const { fragment } = build.compiled!;
|
||||
expect(fragment).toMatch(/float n\d+_result = sqrt\(max\(n\d+_u, 0\.0\)\);/);
|
||||
expect(fragment).toMatch(/vec3 n\d+_result = sqrt\(max\(n\d+_color, 0\.0\)\);/);
|
||||
});
|
||||
|
||||
it('writes Abs as the GLSL call, per channel for a colour', () => {
|
||||
const f = makeProject();
|
||||
const s = shaderEditor(f, 'Fold');
|
||||
|
||||
Reference in new issue
Block a user