vue-avataaars
Version:
A Vue js component for avataaars
295 lines (275 loc) • 8.77 kB
JavaScript
var PERLIN_YWRAPB = 4;
var PERLIN_YWRAP = 1 << PERLIN_YWRAPB;
var PERLIN_ZWRAPB = 8;
var PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB;
var PERLIN_SIZE = 4095;
var perlin_octaves = 4; // default to medium smooth
var perlin_amp_falloff = 0.5; // 50% reduction/octave
var scaled_cosine = function scaled_cosine(i) {
return 0.5 * (1.0 - Math.cos(i * Math.PI));
};
var perlin; // will be initialized lazily by noise() or noiseSeed()
/**
* Returns the Perlin noise value at specified coordinates. Perlin noise is
* a random sequence generator producing a more natural ordered, harmonic
* succession of numbers compared to the standard <b>random()</b> function.
* It was invented by Ken Perlin in the 1980s and been used since in
* graphical applications to produce procedural textures, natural motion,
* shapes, terrains etc.<br /><br /> The main difference to the
* <b>random()</b> function is that Perlin noise is defined in an infinite
* n-dimensional space where each pair of coordinates corresponds to a
* fixed semi-random value (fixed only for the lifespan of the program; see
* the <a href="#/p5/noiseSeed">noiseSeed()</a> function). p5.js can compute 1D, 2D and 3D noise,
* depending on the number of coordinates given. The resulting value will
* always be between 0.0 and 1.0. The noise value can be animated by moving
* through the noise space as demonstrated in the example above. The 2nd
* and 3rd dimension can also be interpreted as time.<br /><br />The actual
* noise is structured similar to an audio signal, in respect to the
* function's use of frequencies. Similar to the concept of harmonics in
* physics, perlin noise is computed over several octaves which are added
* together for the final result. <br /><br />Another way to adjust the
* character of the resulting sequence is the scale of the input
* coordinates. As the function works within an infinite space the value of
* the coordinates doesn't matter as such, only the distance between
* successive coordinates does (eg. when using <b>noise()</b> within a
* loop). As a general rule the smaller the difference between coordinates,
* the smoother the resulting noise sequence will be. Steps of 0.005-0.03
* work best for most applications, but this will differ depending on use.
*
*
* @method noise
* @param {Number} x x-coordinate in noise space
* @param {Number} [y] y-coordinate in noise space
* @param {Number} [z] z-coordinate in noise space
* @return {Number} Perlin noise value (between 0 and 1) at specified
* coordinates
* @example
* <div>
* <code>
* let xoff = 0.0;
*
* function draw() {
* background(204);
* xoff = xoff + 0.01;
* let n = noise(xoff) * width;
* line(n, 0, n, height);
* }
* </code>
* </div>
* <div>
* <code>let noiseScale=0.02;
*
* function draw() {
* background(0);
* for (let x=0; x < width; x++) {
* let noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale);
* stroke(noiseVal*255);
* line(x, mouseY+noiseVal*80, x, height);
* }
* }
* </code>
* </div>
*
* @alt
* vertical line moves left to right with updating noise values.
* horizontal wave pattern effected by mouse x-position & updating noise values.
*
*/
const noise = function(x, y, z) {
y = y || 0;
z = z || 0;
if (perlin == null) {
perlin = new Array(PERLIN_SIZE + 1);
for (var i = 0; i < PERLIN_SIZE + 1; i++) {
perlin[i] = Math.random();
}
}
if (x < 0) {
x = -x;
}
if (y < 0) {
y = -y;
}
if (z < 0) {
z = -z;
}
var xi = Math.floor(x),
yi = Math.floor(y),
zi = Math.floor(z);
var xf = x - xi;
var yf = y - yi;
var zf = z - zi;
var rxf, ryf;
var r = 0;
var ampl = 0.5;
var n1, n2, n3;
for (var o = 0; o < perlin_octaves; o++) {
var of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB);
rxf = scaled_cosine(xf);
ryf = scaled_cosine(yf);
n1 = perlin[of & PERLIN_SIZE];
n1 += rxf * (perlin[(of + 1) & PERLIN_SIZE] - n1);
n2 = perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE];
n2 += rxf * (perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n2);
n1 += ryf * (n2 - n1);
of += PERLIN_ZWRAP;
n2 = perlin[of & PERLIN_SIZE];
n2 += rxf * (perlin[(of + 1) & PERLIN_SIZE] - n2);
n3 = perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE];
n3 += rxf * (perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n3);
n2 += ryf * (n3 - n2);
n1 += scaled_cosine(zf) * (n2 - n1);
r += n1 * ampl;
ampl *= perlin_amp_falloff;
xi <<= 1;
xf *= 2;
yi <<= 1;
yf *= 2;
zi <<= 1;
zf *= 2;
if (xf >= 1.0) {
xi++;
xf--;
}
if (yf >= 1.0) {
yi++;
yf--;
}
if (zf >= 1.0) {
zi++;
zf--;
}
}
return r;
};
/**
*
* Adjusts the character and level of detail produced by the Perlin noise
* function. Similar to harmonics in physics, noise is computed over
* several octaves. Lower octaves contribute more to the output signal and
* as such define the overall intensity of the noise, whereas higher octaves
* create finer grained details in the noise sequence.
* <br><br>
* By default, noise is computed over 4 octaves with each octave contributing
* exactly half than its predecessor, starting at 50% strength for the 1st
* octave. This falloff amount can be changed by adding an additional function
* parameter. Eg. a falloff factor of 0.75 means each octave will now have
* 75% impact (25% less) of the previous lower octave. Any value between
* 0.0 and 1.0 is valid, however note that values greater than 0.5 might
* result in greater than 1.0 values returned by <b>noise()</b>.
* <br><br>
* By changing these parameters, the signal created by the <b>noise()</b>
* function can be adapted to fit very specific needs and characteristics.
*
* @method noiseDetail
* @param {Number} lod number of octaves to be used by the noise
* @param {Number} falloff falloff factor for each octave
* @example
* <div>
* <code>
* let noiseVal;
* let noiseScale = 0.02;
*
* function setup() {
* createCanvas(100, 100);
* }
*
* function draw() {
* background(0);
* for (let y = 0; y < height; y++) {
* for (let x = 0; x < width / 2; x++) {
* noiseDetail(2, 0.2);
* noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale);
* stroke(noiseVal * 255);
* point(x, y);
* noiseDetail(8, 0.65);
* noiseVal = noise(
* (mouseX + x + width / 2) * noiseScale,
* (mouseY + y) * noiseScale
* );
* stroke(noiseVal * 255);
* point(x + width / 2, y);
* }
* }
* }
* </code>
* </div>
*
* @alt
* 2 vertical grey smokey patterns affected my mouse x-position and noise.
*
*/
const noiseDetail = function(lod, falloff) {
if (lod > 0) {
perlin_octaves = lod;
}
if (falloff > 0) {
perlin_amp_falloff = falloff;
}
};
/**
* Sets the seed value for <b>noise()</b>. By default, <b>noise()</b>
* produces different results each time the program is run. Set the
* <b>value</b> parameter to a constant to return the same pseudo-random
* numbers each time the software is run.
*
* @method noiseSeed
* @param {Number} seed the seed value
* @example
* <div>
* <code>let xoff = 0.0;
*
* function setup() {
* noiseSeed(99);
* stroke(0, 10);
* }
*
* function draw() {
* xoff = xoff + .01;
* let n = noise(xoff) * width;
* line(n, 0, n, height);
* }
* </code>
* </div>
*
* @alt
* vertical grey lines drawing in pattern affected by noise.
*
*/
const noiseSeed = function(seed) {
// Linear Congruential Generator
// Variant of a Lehman Generator
var lcg = (function() {
// Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes
// m is basically chosen to be large (as it is the max period)
// and for its relationships to a and c
var m = 4294967296;
// a - 1 should be divisible by m's prime factors
var a = 1664525;
// c and m should be co-prime
var c = 1013904223;
var seed, z;
return {
setSeed: function setSeed(val) {
// pick a random seed if val is undefined or null
// the >>> 0 casts the seed to an unsigned 32-bit integer
z = seed = (val == null ? Math.random() * m : val) >>> 0;
},
getSeed: function getSeed() {
return seed;
},
rand: function rand() {
// define the recurrence relationship
z = (a * z + c) % m;
// return a float in [0, 1)
// if z = m then z / m = 0 therefore (z % m) / m < 1 always
return z / m;
}
};
})();
lcg.setSeed(seed);
perlin = new Array(PERLIN_SIZE + 1);
for (var i = 0; i < PERLIN_SIZE + 1; i++) {
perlin[i] = lcg.rand();
}
};