Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'.
Let’s do it!
8) Signed Distance Functions
Wikipedia: Signed Distance Functions
- Piter explains how to SDFs
- 2D distance functions by Inigo Quilez
- 3D distance functions by Inigo Quilez
Okay, signed distance functions are really cool. Basically you can mathematically describe shapes (I have sdfCircle
and sdfBox
), then combine them (sdfUnion
, sdfIntersect
, and sdfSubtract
) and then render that.
Check out the code for this one. I’m going to have to do more with it.
Just for fun, there’s a bit of noise
that’s wiggling the x/y
around (that’s why it stays fuzzy).
function setup() {
createCanvas(400, 400);
background(0);
}
function draw() {
// Draw 1000 dots per frame
for (let k = 0; k < 1000; k++) {
// Choose a random point [-1, 1]
let ox = 2 * random() - 1;
let oy = 2 * random() - 1;
let x = ox;
let y = oy;
x += noise(frameCount / 100.0, 0) / 10.0 - 0.05;
y += noise(frameCount / 100.0, 1) / 10.0 - 0.05;
// Calculate the SDF at that point
let d = sdfUnion(
// S top
sdfSubtract(
sdfCircle([x, y], [-0.5, -0.35], 0.4),
sdfCircle([x, y], [-0.5, -0.35], 0.3),
sdfBox([x, y], [0, 0], [0.5, 0.5])
),
// S bottom
sdfSubtract(
sdfCircle([x, y], [-0.5, 0.35], 0.4),
sdfCircle([x, y], [-0.5, 0.35], 0.3),
sdfBox([x, y], [-1, 0], [0.5, 0.5])
),
// D round
sdfSubtract(
sdfCircle([x, y], [-0.2, 0], 0.5),
sdfCircle([x, y], [-0.2, 0], 0.4),
sdfBox([x, y], [-0.7, 0], [0.5, 1])
),
// D line
sdfBox([x, y], [-0.2, 0], [0.05, 0.5]),
// F vertical
sdfBox([x, y], [0.3, 0], [0.05, 0.75]),
// F top
sdfBox([x, y], [0.55, -0.7], [0.3, 0.05]),
// F middle
sdfBox([x, y], [0.45, -0.2], [0.2, 0.05])
);
// Assign a color based on if we're inside/outside/at the line
let c = '#000';
if (d < -0.01) c = '#c6c';
if (d > 0.01) c = '#0f4';
// Draw a dot, recenter on the center of the screen
noStroke();
fill(c);
circle(
(1.0 + ox) * width / 2,
(1.0 + oy) * height / 2,
2);
}
}
/* HELPER FUNCTIONS */
function sdfDistance(x, y) {
return (x * x + y * y) ** 0.5;
}
function sdfEdge(a, b) {
return a > 0 && b > 0 ? sdfDistance(a, b) : a > b ? a : b;
}
/* SHAPES */
// Draw a circle at the given point, offset, and radius
function sdfCircle([x,y], [cx, cy], r) {
x -= cx;
y -= cy;
return sdfDistance(x, y) - r;
}
// Draw a box at the given point, offset, and width/height
function sdfBox([x,y], [cx, cy], [w, h]) {
x -= cx;
y -= cy;
return sdfEdge(abs(x) - w, abs(y) - h);
}
/* COMBINATORS */
function sdfUnion() {
return min(...arguments);
}
function sdfSubtract() {
return max(...[...arguments].map((v, i) => i == 0 ? v : -1 * v));
}
function sdfIntersect() {
return max(...arguments);
}
Posts in Genuary 2023:
- Genuary 2023.01: Perfect loop
- Genuary 2023.02: Made in 10 minutes
- Genuary 2023.03: Glitch art
- Genuary 2023.04: Intersections
- Genuary 2023.05: Debug view
- Genuary 2023.06: Steal like an artist
- Genuary 2023.07: Sample a color palette
- Genuary 2023.08: Signed Distance Functions
- Genuary 2023.09: Plants
- Genuary 2023.10: Generative Music
- Genuary 2023.11: Suprematism
- Genuary 2023.12: Tessellation
- Genuary 2023.13: Something you've always wanted to learn
- Genuary 2023.14: Asemic Writing
- Genuary 2023.15: Sine Waves
- Genuary 2023.16: Reflections of a Reflection
- Genuary 2023.17: A grid inside a grid inside a grid
- Genuary 2023.18: Definitely not a grid
- Genuary 2023.19: Black and white
- Genuary 2023.20: Art Deco
- Genuary 2023.21: Persian Carpet
- Genuary 2023.22: Shadows
- Genuary 2023.23: Moiré
- Genuary 2023.24: Textile
- Genuary 2023.25: Yayoi Kusama
- Genuary 2023.26: My kid could have made that
- Genuary 2023.27: In the style of Hilma Af Klint
- Genuary 2023.28: Generative poetry
- Genuary 2023.29: Maximalism
- Genuary 2023.30: Minimalism
- Genuary 2023.31: Break a previous image