JavaScript simplex / perlin noise
Asked Answered
P

3

20

I'm trying to create a perlin / simplex / value noise function in JavaScript that will give results similar to the following:

enter image description here (Note: this image has already had a treshold applied. I want it without the treshold.)

I've been looking all over the internet for 2 days now. There are plenty of links explaining noise and a lot of code, but none in JavaScript, and whenever I try to convert it, I get weird results. Here are some of my attemps:

I think part of the problem might stem from the use of the bitwise operators in JavaScript, where it is difficult to enforce the type of a number.

What I'm looking for is an example of working, JavaScript noise (whatever type).

I'd also be willing to grant a bounty for any information pertaining to the parameters that could lead to a pattern similar to the image I posted (before threshold) or any optimization tips since I'll need this to run as fast as possible (in JavaScript nonetheless).

Primero answered 6/12, 2011 at 19:21 Comment(1)
I will be using the code found on this Gist.Primero
E
6

I know this is pretty old, but maybe it can still be useful for someone else. I've built a javascript app that renders Perlin and Simplex noise to an HTML5 canvas, check it out here: http://lencinhaus.github.io/canvas-noise

The app allows you to tweak every parameter involved in noise calculation and rendering and to save the resulting texture. It also adds the parameters to the URL, so that it can be shared. For example, this configuration produces a texture very similar to the one you have provided.

Expectancy answered 22/3, 2013 at 0:38 Comment(1)
Do you mind pasting the relevant code in your answer? The link is long dead and the answer is no longer helpful unless the link is updated or the code is added to the answer.Conquian
J
4

Here's what the code I ended up with for 2D / 3D Perlin noise. Note that it uses RequireJS's AMD module syntax, but you can strip that away if you're not using an AMD loader.

define(
    [],
    function()
    {
        function fade(t)
        {
            return t * t * t * (t * (t * 6 - 15) + 10);
        }

        function lerp(t, a, b)
        {
            return a + t * (b - a);
        }

        function grad(hash, x, y, z)
        {
            // Convert lo 4 bits of hash code into 12 gradient directions.
            var h = hash & 15,
                u = h < 8 ? x : y,
                v = h < 4 ? y : h == 12 || h == 14 ? x : z;
            return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
        }

        function scale(n)
        {
            return (1 + n) / 2;
        }

        var p = new Array(512);

        var permutation = [
            151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99,
            37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
            57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166,
            77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
            54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159,
            86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82,
            85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44,
            154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
            178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51,
            145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45,
            127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
        ];

        for (var i = 0; i < 256; i++) {
            p[256 + i] = p[i] = permutation[i];
        }

        return {
            /** Returns a number between 0 and 1. */
            noise3d: function(x, y, z)
            {
                // Find unit cube that contains point.
                var X = Math.floor(x) & 255,
                    Y = Math.floor(y) & 255,
                    Z = Math.floor(z) & 255;
                // Find relative x,y,z of point in cube.
                x -= Math.floor(x);
                y -= Math.floor(y);
                z -= Math.floor(z);
                // Compute fade curves for each of x,y,z.
                var u = fade(x),
                    v = fade(y),
                    w = fade(z);
                // Hash coordinates of the corners.
                var A = p[X    ] + Y, AA = p[A] + Z, AB = p[A + 1] + Z,
                    B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;

                // Add blended results from 8 corners of cube.
                return scale(
                    lerp(
                        w,
                        lerp(
                            v,
                            lerp(
                                u,
                                grad(p[AA], x, y, z),
                                grad(p[BA], x - 1, y, z)
                            ),
                            lerp(
                                u,
                                grad(p[AB], x, y - 1, z),
                                grad(p[BB], x - 1, y - 1, z)
                            )
                        ),
                        lerp(
                            v,
                            lerp(
                                u,
                                grad(p[AA + 1], x, y, z - 1),
                                grad(p[BA + 1], x - 1, y, z - 1)
                            ),
                            lerp(
                                u,
                                grad(p[AB + 1], x, y - 1, z - 1),
                                grad(p[BB + 1], x - 1, y - 1, z - 1)
                            )
                        )
                    )
                );
            },

            /** Returns a number between 0 and 1. */
            noise2d: function(x, y)
            {
                // Find unit square that contains point.
                var X = Math.floor(x) & 255,
                    Y = Math.floor(y) & 255;
                // Find relative x,y of point in square.
                x -= Math.floor(x);
                y -= Math.floor(y);
                // Compute fade curves for each of x,y.
                var u = fade(x),
                    v = fade(y);
                // Hash coordinates of the corners.
                var A = p[X    ] + Y, AA = p[A], AB = p[A + 1],
                    B = p[X + 1] + Y, BA = p[B], BB = p[B + 1];

                // Add blended results from the corners.
                return scale(
                    lerp(
                        v,
                        lerp(
                            u,
                            grad(p[AA], x, y, 0),
                            grad(p[BA], x - 1, y, 0)
                        ),
                        lerp(
                            u,
                            grad(p[AB], x, y - 1, 0),
                            grad(p[BB], x - 1, y - 1, 0)
                        )
                    )
                );
            }
        };
    }
);
Jasminejason answered 18/10, 2012 at 22:45 Comment(0)
B
1

I came up with this solution which gave better results for my use case:

http://asserttrue.blogspot.com/2011/12/perlin-noise-in-javascript_31.html

It's using a big permutation matrix:

var permutation = [ 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
];

Use it as:

pn = PerlinNoise()
n = pn.noise( random_x, random_y, .8 )
Beanfeast answered 8/11, 2018 at 22:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.