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

noise() generic function #42

Open
abernier opened this issue Nov 26, 2021 · 4 comments
Open

noise() generic function #42

abernier opened this issue Nov 26, 2021 · 4 comments

Comments

@abernier
Copy link

abernier commented Nov 26, 2021

what about a "generic" noise function, with variable-length arguments, ie:

generic implied comment
noise() noise2D(0, 0) 0 by default
noise(1) noise2D(1,1) same value for 2nd arg
noise(1,2) noise2D(1,2)
noise(1,2,3) noise3D(1,2,3)
noise(1,2,3,4) noise4D(1,2,3,4)
noise(1,2,3,4,5) noise4D(1,2,3,4,5) NB: when more than 4 args => 5th, 6th... will just be ignored by noise4D

This is inspired from https://processing.org/reference/noise_.html

function noise(...args) {
  let dim // 2 or 3 or 4
  let args2 = [...args] // copy of args
  
  if (args.length < 2) {
    // 0 or 1 arg => noise2d
    const arg = args[0] || 0
    args2 = [arg, arg]
    dim = 2
  } else {
    // 2 or 3 or 4 or more args => noise2D or noise3D or noise4D
    dim = Math.min(args.length, 4)
  }
  
  return simplex[`noise${dim}D`](...args2) /2 + 0.5 // normalize [0;1]
}

NB: I've chosen to normalise the value to ]0;1[ but maybe you prefer staying ]-1;1[

working demo: https://codepen.io/abernier/pen/ExvqNyj

@jwagner
Copy link
Owner

jwagner commented Nov 27, 2021

Hi @abernier ,

Thanks for your suggestion. I'm not quite sure I see the benefits outweighing the drawbacks of this extension. Here are the drawbacks I can see:

As suggested noise() is very slow. It leads to a ~4x reduction in speed for the 2d case. Even just calling noise2D would be quicker:

noise2D: 50,350,911 ops/sec ±0%
noise4D: 21,945,180 ops/sec ±0%

That could be addressed to some extent by turning it into a simple switch case.
It also makes optimizations for bundlers more difficult because it's harder to determine which code is unused. At least for now this is a minor issue since afaik no bundler/minimizer performs dead code elimination on a method level.

The signature suggests that the function can handle more than 4 dimensions which isn't true.

Finally it would add multiple ways to achieve the same goal.

What are the benefits and drawbacks you see to this change?

@abernier
Copy link
Author

Yeah, I didn't even considered it on the performance point of vue...

It was more like a kind of optional "smart"/"magic" call, obviously slower then.

I understand your concerns, please just ignore then ;)

@jwagner
Copy link
Owner

jwagner commented Nov 28, 2021

Just to be clear, performance really isn't the be all end all of this discussion. Performance can be improved by writing stupid enough code for jit to understand:

function fasterNoise(x,y,z,w) {
  if(x === undefined) return 0;
  if(y === undefined) return simplex.noise2D(x,x);
  if(z === undefined) return simplex.noise2D(x,y);
  if(w === undefined) return simplex.noise3D(x,y,z);
  return simplex.noise4D(x,y,z,w);
}
noise: 13,020,651 ops/sec ±0%
fasterNoise: 50,688,165 ops/sec ±0%
noise2D: 50,697,667 ops/sec ±0%

I'll leave this issue open for a while for others to weigh in as well. Just because I'm not a fan doesn't mean this isn't something other users would like to see. :)

@SReject
Copy link

SReject commented May 26, 2022

I think this is better left up to the end-user. Not on the basis of performance, but code clarity. Resulting code becomes ambiguous as to its purpose when you abstract away the interface.

With that said, though not tested, a slight improvement to jwagner's implementation may be to encapsulate the various noise functions:

const MagicNoise = simplex => {
  const { noise2D, noise3D, noise4D } = simplex;
  return (x, y, z, w) => {
    if (x === undefined) return 0;
    if (y === undefined) return noise2D(x, x);
    if (z === undefined) return noise2D(x, y);
    if (w === undefined) return noise3D(x, y, z);
    return noise4D(x, y, z, w);
  };
};

// usage
const noise = MagicNoise(new SimplexNoise('seed'));
noise(1,1);

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

3 participants