@@ -118,6 +118,59 @@ inline float udBezier(float2 pos, float2 A, float2 B, float2 C )
118118 return sqrt ( res );
119119}
120120
121+ inline float3 solveCubic (float a, float b, float c)
122+ {
123+ float p = b - a*a / 3.0 , p3 = p*p*p;
124+ float q = a * (2.0 *a*a - 9.0 *b) / 27.0 + c;
125+ float d = q*q + 4.0 *p3 / 27.0 ;
126+ float offset = -a / 3.0 ;
127+ if (d >= 0.0 ) {
128+ float z = sqrt (d);
129+ float2 x = (float2{z, -z} - q) / 2.0 ;
130+ float2 uv = sign (x)*pow (abs (x), float2 (1.0 /3.0 ));
131+ return float3 (offset + uv.x + uv.y );
132+ }
133+ float v = acos (-sqrt (-27.0 / p3) * q / 2.0 ) / 3.0 ;
134+ float m = cos (v), n = sin (v)*1.732050808 ;
135+ return float3{m + m, -n - m, n - m} * sqrt (-p / 3.0 ) + offset;
136+ }
137+
138+ inline float sdBezier (float2 A, float2 B, float2 C, float2 p)
139+ {
140+ // Offset to avoid degeneracy when B == midpoint(A, C)
141+ B = mix (B + float2 (1e-4 ), B, step (float2 (1e-6f ), abs (B * 2.0 - A - C)));
142+
143+ float2 a = B - A;
144+ float2 b = A - 2.0 * B + C;
145+ float2 c = 2.0 * a;
146+ float2 d = A - p;
147+
148+ float3 k = float3{3 .0f * dot (a, b),
149+ 2 .0f * dot (a, a) + dot (d, b),
150+ dot (d, a)} / dot (b, b);
151+
152+ float3 t = clamp (solveCubic (k.x , k.y , k.z ), 0.0 , 1.0 );
153+
154+ float minDist = 1e10 ;
155+ float bestT = 0.0 ;
156+ for (int i = 0 ; i < 3 ; ++i) {
157+ float ti = i == 0 ? t.x : (i == 1 ? t.y : t.z );
158+ float2 qi = A + (c + b * ti) * ti; // Evaluate position on curve
159+ float di = length (qi - p);
160+ if (di < minDist) {
161+ minDist = di;
162+ bestT = ti;
163+ }
164+ }
165+
166+ // Evaluate curve and tangent at bestT
167+ float2 pos = A + (c + b * bestT) * bestT;
168+ float2 tangent = normalize (2.0 * mix (B - A, C - B, bestT));
169+ float2 diff = normalize (pos - p);
170+
171+ return minDist * sign (tangent.x * diff.y - tangent.y * diff.x );
172+ }
173+
121174inline float sdSubtract (float d1, float d2)
122175{
123176 return max (-d1, d2);
0 commit comments