2D SDF(5): Regular Star - OhBonsai/art GitHub Wiki
- geogebra https://www.geogebra.org/classic/bvcg52pn
- shadertoy https://www.shadertoy.com/view/MfyGzW
The derivation of SDF for a generic star is very similar with regular ploygon. mainly involving three key points:
- Poloar coordinate transformation
- Leveraging symmetry to simplify calculations
- Reducing the problem to the derivation of SDF for a Segment
As shown in the diagram above, the position of
vec2 cartesianToPolar(vec2 cartesianCoords) {
float r = length(cartesianCoords); // Radial distance
float theta = atan(cartesianCoords.y, cartesianCoords.x); // Angle in radians
return vec2(r, theta);
}
vec2 polarToCartesian(vec2 polarCoords) {
float x = polarCoords.x * cos(polarCoords.y); // r * cos(theta)
float y = polarCoords.x * sin(polarCoords.y); // r * sin(theta)
return vec2(x, y);
}
Aussuming the current star shape has N angles, with an inner raidus of inRadius
and a outer raidus of outRadius
. Thus we have
The Polar coordinates for
From this, we have the following code
float sdf_star(vec2 P, float outRadius, float inRadius, int sides) {
float angle = atan(P.y, P.x);
angle = P.y > 0. ? angle: angle + PI * 2.;
float delta = 2. * PI / float(sides);
float theta = mod(angle, delta) - delta / 2.0;
float pieceIdx = floor(angle / delta);
// start angle of current piece
float theta3 = delta * pieceIdx;
vec2 polar_P1 = vec2(outRadius, theta3);
vec2 polar_P4 = vec2(inRadius, delta/2.0+theta3);
// p and symmetrical p
float theta2 = delta / 2.0 - abs(theta) + theta3;
vec2 polar_P = vec2(length(P), theta2);
// point
vec2 P0 = polarToCartesian(polar_P);
// segment a,b
vec2 P1= polarToCartesian(polar_P1);
vec2 P4= polarToCartesian(polar_P4);
//segment sdf
vec2 v1 = P0 - P4;
vec2 v2 = P1 - P4;
float h = clamp(dot(v1,v2)/dot(v2,v2), 0.0, 1.0);
return sign(cross2(v2, v1)) * length(v1-h*v2);
}
Finally, We got this :)