Public
Edited
Feb 24, 2023
Importers
3 stars
Insert cell
Insert cell
function noise1d (x) {

// Get the integer component of x to tell us which "unit" of we're in.
const _x = Math.floor(x);
// Treat x as the distance within that unit length.
x = x - _x;

// For each unit coordinate genreate a pseudo random gradient vector.
// This part I haven't done exactly like the perlin algorithm, but it boils down to something pretty similar.
const g1 = cells1d[(_x) % nUnique];
const g2 = cells1d[(_x+1) % nUnique];

// Linearly interpolate between g1 and g2 to give our output.
return lerp(g1, g2, fade(x))
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function noise2d(x, y) {
// get our position within the unit space.
const _x = Math.floor(x);
const _y = Math.floor(y);
x = x - _x;
y = y - _y;
// Get the x and y cooridnates of the left and right, top and bottom of the cell
// Taking the modulo of these by nUnique gives us noise that repeats every nUnique units.
const _x0 = _x % nUnique;
const _y0 = _y % nUnique;
const _x1 = (_x + 1) % nUnique;
const _y1 = (_y + 1) % nUnique;

// Get our gradient vectors
const g00 = cells2d[_x0 + perm[_y0]]
const g10 = cells2d[_x1 + perm[_y0]]
const g01 = cells2d[_x0 + perm[_y1]]
const g11 = cells2d[_x1 + perm[_y1]]

// Get the displacement between a given point and the four corners of the cell
const d00 = [x, y];
const d10 = [x-1, y];
const d01 = [x , y-1];
const d11 = [x-1, y-1];

// Compute the influence of each corner on a given point.
const in00 = dot(g00, d00);
const in10 = dot(g10, d10);
const in01 = dot(g01, d01);
const in11 = dot(g11, d11);

// Finally interpolate betweeen our influences. First on the x axis for the top and bottom pairs of points
const l1 = lerp(in00, in10, fade(x));
const l2 = lerp(in01, in11, fade(x));
// Then on the y axis to fade from left to right.
return lerp(l1, l2, fade(y)) + 0.5;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function noise2DOctaves(x, y, octaves=2, persistence=1.0) {
var total = 0;
var frequency = 1;
var amplitude = 1;
var maxValue = 0;
for (let i=0;i<octaves;i++) {
total += noise2d(x * frequency, y * frequency) * amplitude;
maxValue += amplitude; // Keep track of the maximum amplitude that could have been achieved.
amplitude = amplitude * persistence; // For each step in frequency, increase the amplitude by a factor of the persistence.
frequency = frequency * 2; // Double the frequency
}
return total / maxValue;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
cells2d = cells2Base.map(d => rotate(d, theta / 360 * 2 * Math.PI))
Insert cell
cells2Base = {
// This acts as the source for cells2d, allowing us to rotate cells2d without picking new random values.
var cells = [];
for (let i=0;i<(nUnique * 2);i++) {
cells.push([(Math.random() - 0.5) * 2, (Math.random() - 0.5) * 2]);
}
return cells;
}
Insert cell
cells1d = {
// Actas as a lookup for the random 1D value
var cells = [];
for (let i=0;i<nUnique;i++) {
cells.push(Math.random());
}
return cells;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more