Skip to content
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

Add the ability to generate noise textures #7331

Open
4 of 17 tasks
RandomGamingDev opened this issue Oct 22, 2024 · 5 comments
Open
4 of 17 tasks

Add the ability to generate noise textures #7331

RandomGamingDev opened this issue Oct 22, 2024 · 5 comments

Comments

@RandomGamingDev
Copy link
Contributor

Increasing access

This would make it easier and more efficient to utilize textures, especially with shaders for WebGL since generating noise with the noise() function or just using the noise() function is often too computationally expensive for many tasks, even when limited to just the CPU.

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

Feature request details

We could create a function corresponding to the noise() function called noiseTexture() that takes in similar parameters to noise(). When WebGL is inaccessible we can generate a texture and write to it from the CPU side, and when WebGL is accessible we can generate a texture attached to an FBO and then use a shader with certain uniform parameters to render to it.

@davepagurek
Copy link
Contributor

How do you feel about exposing random and noise helper functions in user shaders? It'd be a little different than your suggestion of making a texture, but it would possibly be a more familiar pattern to users of CPU noise.

With the shader hooks API, in addition to filling in existing hooks, you can add helper functions in too. So if we had an object with noise and random helpers, e.g. this:

const noise = {
  'float rand': `(float n) {
    return fract(sin(n) * 43758.5453123);
  }`,

  'float rand2': `(vec2 n) { 
    return fract(sin(dot(n, vec2(12.9898, 4.1414)))
      * 43758.5453);
  }`,

  'float noise': `(float p){
    float fl = floor(p);
    float fc = fract(p);
    return mix(rand(fl), rand(fl + 1.0), fc);
  }`,

  'float noise2' `(vec2 n) {
    const vec2 d = vec2(0.0, 1.0);
    vec2 b = floor(n),
    f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
    return mix(
      mix(rand2(b), rand2(b + d.yx), f.x),
      mix(rand2(b + d.xy), rand2(b + d.yy), f.x),
    f.y);
  }`
}

...then users could use it in a shader like this:

// mix in all noise functions
myShader = materialShader().modify({
  ...noise,
  'vec4 getFinalColor': `(vec4 c) {
    c *= noise2(gl_FragCoord.xy * 0.15);
    return c;
  }`
})

A current downside of the hooks API is that its design doesn't currently support overloading, so we'd maybe have to figure out a workaround, or make a different API to add arbitrary helpers that don't look like hooks.

Another idea, more in line with your suggestion of having a texture, we could make a noise shader that works with filter(NOISE) so you could call that on a graphic or framebuffer to fill it with noise?

@RandomGamingDev
Copy link
Contributor Author

RandomGamingDev commented Oct 23, 2024

How do you feel about exposing random and noise helper functions in user shaders? It'd be a little different than your suggestion of making a texture, but it would possibly be a more familiar pattern to users of CPU noise.

With the shader hooks API, in addition to filling in existing hooks, you can add helper functions in too. So if we had an object with noise and random helpers, e.g. this:

const noise = {
  'float rand': `(float n) {
    return fract(sin(n) * 43758.5453123);
  }`,

  'float rand2': `(vec2 n) { 
    return fract(sin(dot(n, vec2(12.9898, 4.1414)))
      * 43758.5453);
  }`,

  'float noise': `(float p){
    float fl = floor(p);
    float fc = fract(p);
    return mix(rand(fl), rand(fl + 1.0), fc);
  }`,

  'float noise2' `(vec2 n) {
    const vec2 d = vec2(0.0, 1.0);
    vec2 b = floor(n),
    f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
    return mix(
      mix(rand2(b), rand2(b + d.yx), f.x),
      mix(rand2(b + d.xy), rand2(b + d.yy), f.x),
    f.y);
  }`
}

...then users could use it in a shader like this:

// mix in all noise functions
myShader = materialShader().modify({
  ...noise,
  'vec4 getFinalColor': `(vec4 c) {
    c *= noise2(gl_FragCoord.xy * 0.15);
    return c;
  }`
})

A current downside of the hooks API is that its design doesn't currently support overloading, so we'd maybe have to figure out a workaround, or make a different API to add arbitrary helpers that don't look like hooks.

Another idea, more in line with your suggestion of having a texture, we could make a noise shader that works with filter(NOISE) so you could call that on a graphic or framebuffer to fill it with noise?

While having noise in a shader without a user having to copy and paste the noise code from another source or do the math themselves would be nice, but it wouldn't fulfill all the requirements that this issue is aiming to solve. I would say that creating a noise shader that works with filter() like filter(NOISE) would be nearly perfect, except the behavior is going to differ from that of a typical filter for P2D since it'll have to be software rendered CPU-side (update: both CPU and GPU filter rendering are possible now so this isn't true), which is why I think it doesn't belong there and should be its own thing in the form of a separate noiseTexture() function.

@davepagurek
Copy link
Contributor

2D filters also use shaders as of last summer, using a WebGL graphic under the hood. With that in mind would it accomplish the issue's goals?

@RandomGamingDev
Copy link
Contributor Author

2D filters also use shaders as of last summer, using a WebGL graphic under the hood. With that in mind would it accomplish the issue's goals?

The previous message made a mistake about how the current p5.js filters work so I edited it. Yes, it'd accomplish the issue's goals.

@davepagurek
Copy link
Contributor

Actually, one other update we'd probably need is a way to pass more settings to the shader, since I think we'd want to have the ability to control the noise scale and octaves.

User-made filter shaders can use setUniform, but the builtin ones, accessed with a constant, don't have access to that, and instead have an optional single numeric parameter that can be passed in. If we make a hardcoded edge case for FILTER where we pass in the current noiseDetail() values that control octaves, then the single numeric parameter could be used to control noise scale?

@processing processing deleted a comment Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants