diff --git a/src/webgl/ShaderGenerator.js b/src/webgl/ShaderGenerator.js index d029ed44ef..084d8626cc 100644 --- a/src/webgl/ShaderGenerator.js +++ b/src/webgl/ShaderGenerator.js @@ -7,6 +7,7 @@ import { parse } from 'acorn'; import { ancestor } from 'acorn-walk'; import escodegen from 'escodegen'; +import noiseGLSL from './shaders/functions/noiseGLSL.glsl'; function shadergenerator(p5, fn) { @@ -1578,6 +1579,7 @@ function shadergenerator(p5, fn) { ], 'sqrt': { args: ['genType'], returnType: 'genType', isp5Function: true}, 'step': { args: ['genType', 'genType'], returnType: 'genType', isp5Function: false}, + 'noise': { args: ['vec2'], returnType: 'float', isp5Function: false }, 'trunc': { args: ['genType'], returnType: 'genType', isp5Function: false}, ////////// Vector ////////// @@ -1629,10 +1631,19 @@ function shadergenerator(p5, fn) { return originalLerp.apply(this, args); // Fallback to normal p5.js lerp } }; + const originalNoise = fn.noise; + fn.noise = function (...args) { + if (!GLOBAL_SHADER?.isGenerating) { + return originalNoise.apply(this, args); // fallback to regular p5.js noise + } + + GLOBAL_SHADER.output.vertexDeclarations.add(noiseGLSL); + GLOBAL_SHADER.output.fragmentDeclarations.add(noiseGLSL); + return fnNodeConstructor('noise', args, { args: ['vec2'], returnType: 'float' }); + }; } - export default shadergenerator; if (typeof p5 !== 'undefined') { diff --git a/src/webgl/shaders/functions/noiseGLSL.glsl b/src/webgl/shaders/functions/noiseGLSL.glsl new file mode 100644 index 0000000000..b8c3bd417b --- /dev/null +++ b/src/webgl/shaders/functions/noiseGLSL.glsl @@ -0,0 +1,29 @@ +// Based on https://github.com/patriciogonzalezvivo/lygia/blob/main/generative/noise.glsl (MIT) +// Adapted for use in p5.strands + +vec2 random2(vec2 st) { + st = vec2(dot(st, vec2(127.1, 311.7)), + dot(st, vec2(269.5, 183.3))); + return -1.0 + 2.0 * fract(sin(st) * 43758.5453123); +} + +float noise(vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + // Four corners in 2D of a tile + vec2 a = random2(i); + vec2 b = random2(i + vec2(1.0, 0.0)); + vec2 c = random2(i + vec2(0.0, 1.0)); + vec2 d = random2(i + vec2(1.0, 1.0)); + + // Smooth interpolation + vec2 u = f * f * (3.0 - 2.0 * f); + + // Mix the results + return mix(mix(dot(a, f - vec2(0.0, 0.0)), + dot(b, f - vec2(1.0, 0.0)), u.x), + mix(dot(c, f - vec2(0.0, 1.0)), + dot(d, f - vec2(1.0, 1.0)), u.x), u.y); +} +