Okay, let's build off of the implicit chamfer thread to demonstrate how you can quickly produce any edge treatment you can dream of using implicit geometry.
— Blake Courter (@bcourter) June 25, 2022
In @ntopology, we'll deliver the holy grail of edge treatments: the C∞ blend.
Previous:https://t.co/uKOXYihBD5
(1/n) pic.twitter.com/UG7sRIbifa
At the intersection of any two SDFs A and B, as happens at an edge, we can define the normalized sum and difference fields:
S = (A + B) / |∇A + ∇B|
D = (A - B) / |∇A - ∇B|
We also have a useful spatial parameter Θ for the edge dihedral angle:
cos(Θ) = ∇A · ∇B
(2/n) pic.twitter.com/Tx0MPxOVy9</p>— Blake Courter (@bcourter) June 25, 2022
S and D form a local coordinate system along the edge. It's the kind of frame we associate with 2D space, an "orthonormal basis" for our cross section.
A and B also create a kind of coordinate system or basis, but they are not perpendicular; rather they follow A and B.
(3/n)</p>— Blake Courter (@bcourter) June 25, 2022
In implicit modeling, when one sees a basis, orthonormal or not, one sees an opportunity for transformation. In explicit modeling, one can directly move geometry around, but with implicits, one must draw a new basis where one wants geometry to be.https://t.co/wsVs4RtVPA
(4/n)</p>— Blake Courter (@bcourter) June 25, 2022
So we have two new normalized bases into which we can inject geometry. Let's start with a circular cross section in our canonical example of a cylinder intersecting a plane.
(5/n) pic.twitter.com/st1Vc0slac</p>— Blake Courter (@bcourter) June 25, 2022
When we map to the (S, D) basis, the cutout of our remapped circle stays circular. When we map to the (A, B) basis, it gets warped to an ellipse based on the dihedral angle.
Notice that the (A, B) basis preserves depth, despite the stretch.
(6/n) pic.twitter.com/M2aZg9ewq5</p>— Blake Courter (@bcourter) June 25, 2022
Let's try the same thing but with an axis-aligned square instead of a circle. While (S, D) produces a chamfer-like groove, the (A, B) field sweeps the square with a vertex resting one each face, stretched along the edge. It self-sizes while preserving depth!
(7/n) pic.twitter.com/8Z9V3wRZYb</p>— Blake Courter (@bcourter) June 25, 2022
The (S, D) map is also useful without an edge. It provides a way to sweep an arbitrary shape along a curve, with the twist along the curve defined by the pair of intersecting implicits.
Here's an Escher lizard swept along the (S, D) or our edge.
(8/n) pic.twitter.com/Jle01m2WBc</p>— Blake Courter (@bcourter) June 25, 2022
To achieve a C∞ blend, we need a curve that's infinitely differentiable and is fully contained in one quadrant.
(I misspoke in tweet 7. That groove is produced by one quadrant of the square, not the diagonal.)
(9/n)</p>— Blake Courter (@bcourter) June 25, 2022
Our high school friend y = 1/x is exactly such a curve. It's implicit form in units of length with the right sign convention for intersection is:
1 - ssqrt(xy) = 0
where ssqrt(t), the signed square root, is:
ssqrt(t) = sign(t) * sqrt(|t|)
(10/n) pic.twitter.com/AMAx5AdQqG</p>— Blake Courter (@bcourter) June 25, 2022
Looking closely at the mapped result, just as 1/x is asymptotic to the x and y axes, our blended body never quite touches the original faces.
I like to think of this operation as rock tumbling.
(11/n) pic.twitter.com/THupVajiBw</p>— Blake Courter (@bcourter) June 25, 2022
The pattern of sum and difference fields arises over and over. Since we're looking at a hyperbola, you might have always wondered how 1/x was related to the x^2 - y^2 = 1 version. Turns out it's just mapping with our normalized S and D fields. https://t.co/YDJ1bKjErh
(12/n)</p>— Blake Courter (@bcourter) June 25, 2022
Now, you can do anything you want to pairs of edges. When unioning instead of intersecting, use the opposite section quadrant.
There are other approaches to blending an arbitrary number of SDFs, as seen in nTop blends (including C∞).
eg https://mercury.sexy/hg_sdf/
(13/n; n=13)</p>— Blake Courter (@bcourter) June 25, 2022
PREVIOUSConstant-Width Chamfer