Drag the blue points to control what slice of 2d perlin noise is rendered on the right.
xxxxxxxxxx
const DragThreshold = 25;
const X = 0;
const Y = 1;
let centerX;
let centerY;
let dragging;
let points = [];
let noiseGraphics;
let geometryRadio;
let noiseFrequencySlider;
let noiseOctivesInput;
let noiseFalloffSlider;
function setup() {
createCanvas(1200, 600);
noFill();
ellipseMode(RADIUS);
centerX = height / 2;
centerY = height / 2;
points.push([centerX, centerY]);
points.push([centerX + height / 4, centerY]);
geometryRadio = createRadio();
geometryRadio.option('Line');
geometryRadio.option('Circle');
geometryRadio.selected('Line');
geometryRadio.position(10, 10);
geometryRadio.input(() => redraw());
let frequencyLabel = createElement('label', 'Noise Frequency: ');
frequencyLabel.position(10, 30);
noiseFrequencySlider = createSlider(1, 50, 2);
noiseFrequencySlider.parent(frequencyLabel);
noiseFrequencySlider.style('vertical-align', 'bottom');
noiseFrequencySlider.input(() => {
redrawNoise();
redraw();
});
let octavesLabel = createElement('label', 'Octaves: ');
octavesLabel.position(10, 60);
noiseOctivesInput = createInput('4', 'number');
noiseOctivesInput.parent(octavesLabel);
noiseOctivesInput.changed(() => {
redrawNoise();
redraw();
});
let falloffLabel = createElement('label', 'Falloff: ');
falloffLabel.position(10, 90);
noiseFalloffSlider = createSlider(0.0, 1.0, 0.5, 0);
noiseFalloffSlider.parent(falloffLabel);
noiseFalloffSlider.style('vertical-align', 'bottom');
noiseFalloffSlider.input(() => {
redrawNoise();
redraw();
});
noiseGraphics = createGraphics(height, height);
noiseGraphics.noStroke();
redrawNoise();
noLoop();
}
function redrawNoise() {
let octaves = int(noiseOctivesInput.value());
let falloff = noiseFalloffSlider.value();
noiseDetail(octaves, falloff);
let noiseScale = noiseFrequencySlider.value();
for (let x = 0; x < height; x += 2) {
for (let y = 0; y < height; y += 2) {
let n = noise(
map(x, 0, height, -noiseScale, noiseScale),
map(y, 0, height, -noiseScale, noiseScale)
);
noiseGraphics.fill(map(n, 0, 1, 0, 255));
noiseGraphics.square(x, y, 2);
}
}
}
function draw() {
let noiseScale = noiseFrequencySlider.value();
image(noiseGraphics, 0, 0);
stroke('red');
strokeWeight(1);
let [x1, y1] = points[0];
let [x2, y2] = points[1];
let dx = x2 - x1;
let dy = y2 - y1;
let angle = atan2(dy, dx);
switch (geometryRadio.value()) {
case 'Line':
{
line(x1, y1, x2, y2);
let len = sqrt(dx ** 2 + dy ** 2);
let interval = len / (width / 2);
for (let i = 0; i < width / 2; i++) {
let n = noise(
map(x1 + cos(angle) * interval * i, 0, height, -noiseScale, noiseScale),
map(y1 + sin(angle) * interval * i, 0, height, -noiseScale, noiseScale)
);
stroke(map(n, 0, 1, 0, 255));
line(width / 2 + i, 0, width / 2 + i, height);
}
}
break;
case 'Circle':
{
let radius = sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
circle(x1, y1, radius);
let interval = TWO_PI / (width / 2);
for (let i = 0; i < width / 2; i++) {
let n = noise(
map(x1 + cos(angle + interval * i) * radius, 0, height, -noiseScale, noiseScale),
map(y1 + sin(angle + interval * i) * radius, 0, height, -noiseScale, noiseScale)
);
stroke(map(n, 0, 1, 0, 255));
line(width / 2 + i, 0, width / 2 + i, height);
}
}
break;
}
stroke('blue');
strokeWeight(6);
point(x1, y1);
point(x2, y2);
}
function mousePressed() {
let closest = getClosestPoint();
if (closest && closest.sqdist < DragThreshold) {
dragging = closest.point;
}
}
function mouseDragged() {
// Update draggable position
if (dragging) {
dragging[X] = mouseX;
dragging[Y] = mouseY;
redraw();
}
}
function mouseReleased() {
dragging = undefined;
}
function getClosestPoint() {
let closest;
for (let i = 0; i < points.length; i++) {
let dx = mouseX - points[i][X];
let dy = mouseY - points[i][Y];
let sqdist = dx * dx + dy * dy;
if (!closest || sqdist < closest.sqdist) {
closest = { sqdist, point: points[i], index: i };
}
}
return closest;
}