2D SDF(5): Regular Star - OhBonsai/art GitHub Wiki

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 $P$ can be diviided into four regions. In fact, it's only necessary to determine the positions of point $P1$ and $P4$ , then use the segment SDF. TO facilitate the calculations. functions for converting between polar coordinates and cartesian coordinate systems ar introduced

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 $$\delta = 2\pi / N$$
The Polar coordinates for $P4$ are $$P4 = (r1, \delta / 2)$$
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 :)

⚠️ **GitHub.com Fallback** ⚠️