Just uploaded “Geometry Morphing Demo 2D” to the library (source code below, too) - the latest version of the distance field drawing pattern started in the “Circles” thread.

It shows a quick, easy way to draw certain kinds of geometry, and subject it to all kinds of strange and interesting manipulations.

This particular version is a basic demo just to give the flavor: It draws a single geometric shape, rotated using Pixelblaze’s new map transform functions, and smoothly transforms it into to the next type of shape on its list. From here, many things are possible!

## Geometry Morphing Demo 2D

```
/* Geometry Morphing Demo 2D
Smooth transitions between animated geometric shapes.
This pattern shows how to draw and dynamically modify geometric
objects using a pixel shader and signed distance functions. Since this
method scales automatically with the number of available processors, it
is most often used on GPU-based systems. It's also very well suited to
the Pixelblaze's architecture.
For more information, see:
Basic tutorial on this style of rendering:
https://www.shadertoy.com/view/Xl2XWt
Distance functions for many 2D shapes:
https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
MIT License
Take this code and use it to make cool things!
Version Author Date
1.0.0 ZRanger1 08/09/2021
*/
// UI control variables
export var objectSize = 0.4;
export var lineWidth = 0.05;
var filled = 1;
// shape function selection
var numShapes = 6;
var shapeSdf = array(numShapes)
var shapeCompare = array(2);
// animation control
var shape = 0;
var nextShape = 1;
var hue = 0;
var morphClock = 0;
var wait = 0;
var lerpPct = 0;
shapeCompare[0] = (f) => (abs(f) > lineWidth); // unfilled shapes
shapeCompare[1] = (f) => (f > lineWidth); // filled shapes
shapeSdf[0] = circle;
shapeSdf[1] = cross;
shapeSdf[2] = hexStar;
shapeSdf[3] = square;
shapeSdf[4] = triangle;
shapeSdf[5] = hexagon;
function signum(a) {
return (a > 0) - (a < 0)
}
// signed distance functions for various shapes, adapted for 2D.
// Math from https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
function circle(x,y,r) {
return hypot(x,y) - r;
}
function square(x,y,size) {
dx = abs(x) - size; d1 = max(dx,0);
dy = abs(y) - size; d2 = max(dy,0);
return min(max(dx, dy), 0.0) + hypot(d1,d2);
}
function triangle(x,y,r) {
return max((abs(x) * 0.866025) - (y * 0.5), y) - r / 2;
}
function hexagon(x,y,r){
x = abs(x); y = abs(y);
return max((x * 0.5 + y * 0.866025),x) - r;
}
function hexStar(x,y,r) {
// rescale to pointy parts of star
x = abs(x*1.73205); y = abs(y*1.73205);
dot = 2 * min(-0.5*x + 0.866025 * y,0);
x -= dot * -0.5; y -= dot * 0.866025;
dot = 2 * min(0.866025*x + -0.5 * y,0);
x -= dot * 0.866025; y -= dot * -0.5;
x -= clamp(x, r * 0.57735, r * 1.73205);
y -= r;
return signum(y) * hypot(x,y) / 1.73205;
}
// interior distance on this is slightly weird. Still
// looking for a reasonable fix.
function cross(x,y,size) {
x = abs(x); y = abs(y);
if (y > x) { tmp = x; x = y; y = tmp; }
qx = x - size; qy = y - size / 5;
k = max(qy,qx);
if (k > 0) {
wx = max(qx,0); wy = max(qy,0);
return hypot(wx,wy);
} else {
wx = max(size - x,0); wy = max(-k,0);
return -hypot(wx,wy);
}
}
// UI
export function sliderSize(v) {
objectSize = 0.4 * v;
}
export function sliderFilled(v) {
filled = (v >= 0.5);
}
export function sliderLineWidth(v){
lineWidth = 0.25 * v * v;
}
export function beforeRender(delta) {
morphClock += delta
// morph to a new shape every other second...
if (morphClock > 1000) {
if (!wait) {
shape = nextShape; // set to next shape
nextShape = (nextShape+1) % numShapes;
}
morphClock = 0;
wait = !wait;
}
lerpPct = morphClock / 1000;
// rotate entire scene
theta = PI2 * time(0.1);
resetTransform();
translate(-0.5,-0.5);
rotate(theta);
}
export function render2D(index,x,y) {
var d;
var v = 0;
// draw one our shapes, interpolating between two SDFs when switching shapes
if (wait) {
d = shapeSdf[shape](x,y,objectSize);
} else {
d = shapeSdf[shape](x,y,objectSize) * (1-lerpPct) + shapeSdf[nextShape](x,y,objectSize) * lerpPct;
}
// fill or just draw boundary based on UI seting.
if (!shapeCompare[filled](d)) {;
v = 1-(d/lineWidth);
s = 1.5-abs(d)/objectSize
h = d + time(0.1);
}
hsv(h, s, v*v)
}
```