Skip to content

Add GLSL-based noise(vec2) function to p5.strands (#7897) #7921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 8, 2025

Conversation

LalitNarayanYadav
Copy link
Contributor

Summary

This PR implements a noise(vec2) function in p5.strands to enable shader-compatible noise effects. It addresses #7897, which is part of the broader effort to bridge core p5.js functions with p5.strands (#7849).


Changes Made

  • Created src/webgl/shaders/functions/noise.glsl.js with a basic fractal noise implementation (3 octaves).
  • Registered noise(vec2) in builtInGLSLFunctions in ShaderGenerator.js with isp5Function: false.
  • Injected the GLSL noise code into all fragment shaders via GLOBAL_SHADER.output.fragmentDeclarations.add(noiseGLSL).

PR Checklist

- Created src/webgl/shaders/functions/noise.glsl.js
- Provides a simple fractal noise function using 3 octaves
@LalitNarayanYadav LalitNarayanYadav changed the base branch from main to dev-2.0 June 18, 2025 21:21
@RandomGamingDev
Copy link
Contributor

Looks good to me :D

@davepagurek
Copy link
Contributor

Thanks for tackling this! Are you able to show a test sketch using the noise so we can take a look at what it looks like? Either by making a test sketch in src/preview/global/sketch.js + npm run dev:gloabl, or by running npm run build to generate lib/p5.js and lib/p5.min.js which you could then upload to the p5 web editor and use.

@@ -1632,6 +1634,7 @@ function shadergenerator(p5, fn) {
}


GLOBAL_SHADER.output.fragmentDeclarations.add(noiseGLSL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might not be defined yet, as we only set GLOBAL_SHADER = this in the ShaderGenerator constructor. Maybe rather than adding noise to the list of glsl functions, we could do a custom function for it like you did earlier for lerp, and in that custom function, you do GLOBAL_SHADER.output.fragmentDeclarations.add(noiseGLSL)? (And possibly add it to the vertex declarations too, it could be used in updating positions as well.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @davepagurek! That makes sense. I’ve moved the noiseGLSL injection into a custom fn.noise function wrapper, similar to what was done for lerp. That way it’s only added during shader generation and avoids undefined GLOBAL_SHADER.

Also working on a test sketch under src/preview/global/sketch.js as suggested. Appreciate the review!

@perminder-17 perminder-17 self-requested a review June 22, 2025 16:44
Copy link
Collaborator

@perminder-17 perminder-17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on this so far, just some minor thoughts and would be good to.

@@ -0,0 +1,15 @@
export default /* glsl */ `
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @LalitNarayanYadav, when you put a .js file inside src/webgl/shaders/ that folder is treated as “raw-GLSL only” during the p5.js build because of the string plugin:

p5.js/rollup.config.mjs

Lines 19 to 20 in 257227f

string({
include: 'src/webgl/shaders/**/*'

So the bundler thinks your .js file is just a literal string, not executable JavaScript. "Probably you could get errors saying export is not defined" or maybe something like that.

Simple fix would be :

  1. Keep JavaScript out of that folder i.e. don't place it inside src/webgl/shaders OR,

  2. Rename your helper to something like noiseGLSL.glsl and import it the same way; it already just contains GLSL text. ( I think this one could be good, what you think)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch @perminder-17!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for pointing that out @perminder-17 and @davepagurek ! I've renamed the file to noiseGLSL.glsl and updated the import accordingly to avoid the Rollup plugin conflict. Let me know if anything else needs adjusting!

@perminder-17 perminder-17 self-requested a review June 28, 2025 08:42
@@ -1629,10 +1631,20 @@ function shadergenerator(p5, fn) {
return originalLerp.apply(this, args); // Fallback to normal p5.js lerp
}
};
fn.noise = function (...args) {
if (GLOBAL_SHADER?.isGenerating) {
Copy link
Collaborator

@perminder-17 perminder-17 Jun 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @LalitNarayanYadav a very small suggestion, we are on the last bits now.

What do you think about having an early return guard. Like rather than doing

if (GLOBAL_SHADER?.isGenerating) {
// your code ....
} else {
// friendly error message 
}

Use an early-return guard inside the function.

Something like :

fn.noise = function (...args) {
if (!GLOBAL_SHADER?.isGenerating) {
// friendly-error messages
return;
}
// Now your code here without else block:
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @perminder-17, great suggestion! I've refactored the function to use an early return guard as you described. Looks much cleaner now.

@perminder-17 perminder-17 self-requested a review July 1, 2025 16:30
Copy link
Collaborator

@perminder-17 perminder-17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's the result looks so far : https://editor.p5js.org/aman12345/sketches/83SNq9iF2 which I think looks nice. Maybe we should merge it if creating a functions directory makes sense @davepagurek ?

@@ -0,0 +1,13 @@
float baseNoise(vec2 st) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we going to have more such functions in the future like noise? I am not sure if we should create a functions directory for it? @davepagurek What's your thought on this one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

off the top of my head I think we were considering at least random(), so I think we can keep this folder structure for that.

@@ -0,0 +1,13 @@
float baseNoise(vec2 st) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @LalitNarayanYadav while I tested it locally, I found that the things are little jittery and we want the noise to be smoother, maybe we just need a different basis for each octave.

e.g. something like the examples here, but, maybe finding where they came from to double check the licenses, or doing something similar but different https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83

fn.noise = function (...args) {
if (!GLOBAL_SHADER?.isGenerating) {
p5._friendlyError(
`It looks like you've called noise() outside of a shader's modify() function.`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noise is also a regular p5 function, so in this case we can call the original implementation, similar to how you did lerp.

@LalitNarayanYadav
Copy link
Contributor Author

Thanks @perminder-17 and @davepagurek for the feedback!

I've updated the GLSL noise to use a smoother implementation based on this MIT-licensed source, and added fallback support for core p5.js noise() when called outside of strands, similar to how lerp is handled. Let me know what you think!

@@ -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 },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in the glsl code, we have a baseNoise() function returning float. So, either you have to rename at the js file or in the glsl file. Probably changing from baseNoise() to noise() in the glsl is what I would prefer.

Copy link
Collaborator

@perminder-17 perminder-17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@perminder-17 perminder-17 merged commit f3ab0ce into processing:dev-2.0 Jul 8, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants