0

I am working on a procedural terrain generator, but the 3d Map is constantly morphing and changing, calling for at least 4d noise (5d if I need to make it loop). I haven't found a good perlin/simplex noise library that will work in this many dimensions, so I thought this would be a good time to learn how those algorithms work. After starting to make my own "perlin" noise, I found a large problem. I need to get a psudo random value based on the nD coordinates of that point. So far I have found solutions online that use the dot product of a single point and a vector generated by the inputs, but those became very predictable very fast (I'm not sure why). I then tried a recursive approach (below), and this worked ok, but I got some weird behavior towards the edges. Recursive 3d randomness attempt:

function Rand(seed  = 123456, deg = 1){
    let s = seed % 2147483647;
    s = s < 1 ? s + 2147483647 : s;
    while(deg > 0){
        s = s * 16807 % 2147483647;
        deg--;
    }

    return (s - 1) / 2147483646;
}
function DimRand(seed, args){
    if(args.length < 2){
        return Rand(seed, args[0]);
    }else{
        let zero = args[0];
        args.shift();
        return DimRand(Rand(seed, zero), args);
    }
}
var T = 1;
var c = document.getElementById('canvas').getContext('2d');
document.getElementById('canvas').height = innerHeight;
document.getElementById('canvas').width = innerWidth;
c.width = innerWidth;
c.height = innerHeight;
var size = 50;
function display(){
    for(let i = 0; i < 20; i ++){
        for(let j = 0; j < 20; j ++){
            var bright = DimRand(89,[i,j])*255
            c.fillStyle = `rgb(${bright},${bright},${bright})`
            c.fillRect(i*size, j*size, size, size);
        }   
    }
    T++;
}


window.onmousedown=()=>{display();}

And here is the result:

Recursive approach The top row was always 1 (White), the 2d row and first column were all 0 (Black), and the 3d row was always very dark (less than ≈ 0.3)

This might just be a bug, or I might have to just deal with it, but I was wondering if there was a better approach.

Bagel03
  • 725
  • 7
  • 22
  • An obvious and ugly approach would be to run the generator long enough to clear its predictable state before using its values. It also looks like you may have cut off a line or two of your example code – Gershom Maes Apr 09 '20 at 18:18
  • @Gershom Whoops, sorry about the cut off lines, I thought about shifting everything over and out of the predictable state, but this brought up a new challenge. To ensure that a player would never realistically meet these edges, I would have to do thousands of loops (line 4) for every single value, and the picture in the question is a very very simplified version of what it is going to do. I was aiming for at least 500 by 500 on the screen, which would be very laggy if we had to do 500,000 calculations on 250,000 pixles at 60fps in the browser. – Bagel03 Apr 09 '20 at 23:05
  • I believe shifting is accomplished with `DimRand(89,[i + shift, j + shift])`? That seems like a negligible change in performance! – Gershom Maes Apr 11 '20 at 17:10
  • It's worth mentioning you may want to use a stateful rng to avoid the performance hit of looping `deg` times each time you need the next result... – Gershom Maes Apr 11 '20 at 17:18
  • Yea, thanks. I think you figured this out, but adding to the coordinates would cause that preformance drop. I'm now using a `Math.sin()` version of the rng just now, which is stateful and it seemed to prevent the predictability. (It might repeat though). The only reason that I didn't start with sine is because I had heard about different environments rounding to different amounts. I dont think it will be an issues though, because these amounts are incredibly small, the number of blocks that will pass a threshold on one environment (becomes a block), and who don't on another is very small. – Bagel03 Apr 12 '20 at 22:09

0 Answers0