/* * * A Perlin Noise generator to dynamically generate a terrian-like effect. * * References: * http://freespace.virgin.net/hugo.elias/models/m_perlin.htm * * Start date: 28 April 2015 * */ var perlin = (function() { 'use strict'; // number of points to generate var _NUMPTS = 101; // number of prime numbers in each array var _NUMPRIMES = 5; // holds the 5, 6 and 10 digit prime numbers let _p5d; let _p6d; let _p10d; // 5 digit prime numbers var _prime5 = [ 15731, 16069, 17579, 31963, 22453]; var _prime6 = [ 789221, 790289, 811081, 211777, 566173]; var _prime10 = [1376312589, 1480028201, 1500450271, 1000075057, 1023465798]; // holds the 100 points var _perlin = []; // initialize the array for (var i = 0; i < _NUMPTS; i++) { _perlin[i] = 0.0; } // get a random number from each of the prime number arrays _p5d = _prime5[Math.floor(Math.random() * 5)]; _p6d = _prime6[Math.floor(Math.random() * 5)]; _p10d = _prime10[Math.floor(Math.random() * 5)]; var _perlin1D = function(persist, octave, x) { var total = 0; var freq = 0; var amp = 0; for (var i = 0; i < octave; i++) { freq = Math.pow(2, i); amp = Math.pow(persist, i); total += _interpolateNoise(x * freq) * amp; } return total; }; /* * interpolatedNoise - performs a successive smoothing functions on the * input value. * * ARGUMENT: * x: float value to be smoothed. */ var _interpolateNoise = function(x) { var intX = Math.floor(x); var fractionX = x - intX; var v1 = _smoothedNoise(intX); var v2 = _smoothedNoise(intX + 1); return _cosineInterpolation(v1, v2, fractionX); }; /* * cosineInterpolation - * * Interpolates between two numbers using a cosine function */ var _cosineInterpolation = function (a, b, x) { var ft = (x * Math.PI); var f = (1 - Math.cos(ft)) * 0.5; return a * (1 - f) + (b * f); }; /* * findNoise - Random number generator. Unlike other RNG this method * will return the same number for the same input. * * ARGUMENTS: * x: an integer value * * RETURNS: * returns a floating point number between -1.0 and 1.0. */ var _findNoise = function(x) { x = (x << 13) ^ x; return (1.0 - ( ( x * (x * x * _p5d + _p6d) + _p10d) & 0x7fffffff ) / 1073741824.0); // original return value as published on // http://freespace.virgin.net/hugo.elias/models/m_perlin.htm }; /* * smoothedNoise - smooths the output to make it look less random * * ARGUMENTS: * x: integer value to be smoothed. It is done by averaging between * the points before and after the given point. * * RETURNS: * a float value that has been "smoothed". */ var _smoothedNoise = function(x) { return (_findNoise(x) /2) + (_findNoise(x - 1) / 4) + _findNoise(x+1)/4; }; var perlinNoise1D = function(persist, octave) { for (var i = 0; i < _NUMPTS; i++) { _perlin[i] = _perlin1D(persist, octave, 0.1 * i); } return _perlin; }; /* * draw the "terrain" on the given context */ var draw = function(context, width, height, color, fill) { if (context === undefined) return null; if (color === undefined) color = '#000000'; // black if (width === undefined) width = 400; if (height === undefined) height = 400; if (fill === undefined) fill = true; var step = width / _NUMPTS; context.lineWidth = 1; context.strokeStyle = color; // start drawing at the bottom left corner context.beginPath(); context.moveTo(0, height); for (var i = 0; i < _NUMPTS; i++) { context.lineTo(step * i, height / 2 + _perlin[i] * height / 2); } context.lineTo(width, height / 2 + _perlin[_NUMPTS - 1] * height / 2); context.lineTo(width, height); context.closePath(); context.stroke(); if (fill) { context.fillStyle = color; context.fill(); } }; // public functions return { perlinNoise1D: perlinNoise1D, draw: draw }; })(); var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); canvas.width = 800; canvas.height = 400; function drawTerrain() { var octave = document.getElementById('octave'); octave.addEventListener("change", generate, false); var persist = document.getElementById('persist'); persist.addEventListener("change", generate, false); function generate() { context.clearRect(0, 0, canvas.width, canvas.height); perlin.perlinNoise1D(persist.value, octave.value); perlin.draw(context, canvas.width, canvas.height); } } function eventWindowLoaded() { perlin.perlinNoise1D(0.3, 4); perlin.draw(context, canvas.width, canvas.height); drawTerrain(); let perlin1 = new (perlin.perlinNoise1D(0.3, 4))(); console.log("perlin1:"); console.log(perlin1); let perlin2 = new (perlin.perlinNoise1D(0.3, 4))(); console.log("perlin2"); console.log(perlin2); } window.addEventListener("load", eventWindowLoaded, false); //var pts = perlin.perlinNoise1D(0.3, 1); //perlin.draw(context, canvas.width, canvas.height);