- geogebra www.geogebra.org/classic/bvc…
- shadertoy www.shadertoy.com/view/MfyGzW
SDF推导通用星型与通用正多边形非常类似,主要有三个关键点
- 极坐标转换
- 利用对称性简化运算
- 把问题简化到Segement的SDF推导
如上图所示,P点的位置可以分为4个区域,实际上只需要求出 点的位置,再利用线段SDF加上向量方向判断距离正负号即可。 为了方便运算引入极坐标与笛卡尔坐标系的转化函数
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);
}
假定当前星形的边为N
, 内径为r1
, 外径为r2
。
于是有
P4$ 极坐标为$
P4 = (r1, \delta / 2)$$
于是有以下代码
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 :)