Hello Folks! I was studying SDF from some resources like this:
youtube.com/watch?v=KRB57wyo8_4
openprocessing.org/sketch/1898567
What I want is to try to understand a little more how SDFs work. What I want to do it to get the vertex coordinates to drawing the continues lines that makes the contour of the shape: is something like this:
doing this in a shader is easy, even using only dots with different colors in p5. But i want draw the paths with equidistant lines just like the example. I was trying two approaches. One drawing a grid and rotating vectors, making a flow field, and another from random points. The two strategies are what the open processing sketch uses. But how can I do to generate equidistant lines?
i feel that i missing something. A different approach maybe? My plan is for example, set different frequencies of the SDF and play whit the shapes. Here the sketch i was working.
let R = (a=1)=>Math.random()*a
function setup() {
createCanvas(400, 400);
}
function draw_circle([x,y],r,c) {
noStroke(); fill(c);
circle((x+1)*width/2, (y+1)*width/2, r/2);
}
function sdf_circle([x,y],[cx,cy],r){
x-=cx
y-= cy
return abs(dist(0,0,x,y))-r
}
function sdf_rep(x,r){
x/=r
x -= Math.floor(x)+0.5
x*=r
return x
}
function sdf([x,y]){
let c = sdf_circle([x,y],[0,0],0.3)
let b = sdf_box([x,y], [0.3,0], [0.5,0.4])
c = min(b,c)
// c = abs(sdf_rep(c,0.1))
return c
}
function sdf_box([x,y], [cx,cy], [w,h]) {
x -= cx;
y -= cy;
return max(abs(x)-w, abs(y)-h);
}
function draw() {
// background(220);
// for(let k = 0; k<100;k++){
// let p = [R(2)-1,R(2)-1]
// let d = sdf(p)
// let c = '#000'
// if(d<-.005)c = '#009099'
// if(d>.005)c = '#fff911' ;
// draw_circle(p,2,c)
// }
// noLoop()
// field(25)
// flowRandom(2, 5, 10)
flowSVG(2, 5, 10)
}
function flowRandom(ppf, l, count) {
let gap = 0.02; // 0 thickness
let strokelen = l * 2 / width;
for (let i = 0; i < ppf; i++) {
let gX = R(2)-1
let gY = R(2)-1
let gX0 = gX;
let gY0 = gY;
for (let h = 0; h < count; h++) {
let d = sdf([gX, gY]);
let dx = sdf([gX + 2 / width, gY]);
let dy = sdf([gX, gY + 2 / height]);
let a = atan2(d - dx, d - dy);
let gXN = gX + cos(a) * strokelen;
let gYN = gY - sin(a) * strokelen;
//convert to screen coordinates
let X1 = width * (gX + 1.0) / 2.0;
let Y1 = height - height * (gY + 1.0) / 2.0;
let X2 = width * (gXN + 1.0) / 2.0;
let Y2 = height - height * (gYN + 1.0) / 2.0;
stroke(0);
line(X1, Y1, X2, Y2);
gX = gXN;
gY = gYN;
}
gX = gX0;
gY = gY0;
}
}
function field(divs) { // based on -1..1, -1..1, positive y is up
let gap = 2.0 / divs;
for (let j = 0; j < divs; j++) {
for (let i = 0; i < divs; i++) {
let gX = -1 + i * gap;
let gY = -1 + j * gap;
let d = sdf([gX, gY]);
let dx = sdf( [gX + gap / 100, gY]);
let dy = sdf([gX, gY + gap / 100]);
let a = atan2(d - dx, d - dy);
//convert to screen coordinates
let X1 = width * (gX + 1.0) / 2.0;
let Y1 = height - height * (gY + 1.0) / 2.0;
let X2 = X1 + 0.8 * cos(a) * width / divs;
let Y2 = Y1 + 0.8 * sin(a) * height / divs;
beginShape(LINES)
vertex(X1,Y1)
vertex(X2,Y2)
endShape()
}
}
}
function flowSVG(ppf, l, count) {
let gap = 0.005; // 0 thickness
let strokelen = l * 2 / width; // pixels to drawing units
for (let i = 0; i < ppf; i++) {
let gX = R(2)-1
let gY = R(2)-1
let gX0 = gX;
let gY0 = gY;
if ((sdf([gX,gY])) > gap) {
stroke(random(255),random(255),random(255));
} else {
stroke(random(255));
}
let pointstack = [];
for (let h = 0; h < count; h++) {
let d = sdf([gX,gY])
let dx = sdf([gX + 2 / width, gY]);
let dy = sdf([gX, gY + 2 / height]);
let a = atan2(d - dx, d - dy);
let gXN = gX + cos(a*1) * strokelen;
let gYN = gY - sin(a*1) * strokelen;
//convert to screen coordinates
let X1 = map(gX, -1, 1, 0, width);
let Y1 = map(gY, -1, 1, height, 0);
let X2 = map(gXN, -1, 1, 0, width);
let Y2 = map(gYN, -1, 1, height, 0);
if ((constrain(X2, 0, width) == X2) && (constrain(Y2, 0, height) == Y2)) {
pointstack.push([X2, Y2]);
} else { // hit edge, stop
h = count;
}
gX = gXN;
gY = gYN;
}
noFill()
beginShape();
for (let h = 0; h < pointstack.length; h++) {
vertex(pointstack[h][0], pointstack[h][1]);
}
endShape();
}
}