Last modified: 2025-04-15 14:28:21
< 2025-04-14 2025-04-18 >I wondered about making a "Consolidate" modifier which will turn its child object into just a single surface. Not really sure what it would be useful for, maybe "locking" some targeted blends so that they can't get undone by the tree rewriter?
Cool, works.
Other things that should use half-spaces to get multiple surfaces for blending include:
Good, done.
And then it would be cool if Sketch's had a different surface id on each edge so that
they can have blends as well. Not sure how easy that is to do because we don't just
want min()
of all the edges, we also need to collect up the "sign" to work out whether
the point is inside or outside. Forget it for now.
Propagating distance fields in grids
Assume we start with an empty grid (every cell filled with "unknown" or something). Then by some method we classify cells as "inside" or "outside".
How do we populate it with distances efficiently?
The other day I wrote:
at each pixel/voxel you store not just the distance to the nearest point, but also the coordinates of that point, then you can propagate distances from a neighbour by checking for each of the neighbours' closest points, which one is closest to you. So initialise the grid only along the boundary of the surface, and then propagate the rest with a BFS?
Close, but you don't want BFS. You want one forwards pass (top-left to bottom-right) followed by one backwards pass (bottom-right to top-left). This is apparently called Danielsson's Euclidean distance transform.
https://perso.telecom-paristech.fr/bloch/ANIM/Danielsson.pdf
Oh, and apparently it actually has errors! It doesn't always find the true distance to the nearest point. I can not understand how it can be wrong though, and ChatGPT is not doing a good job of explaining it.
I got Claude to implement the "4SED" version, the code looks fine, although "DistanceDeformInside" seems broken now?
I think it is actually ImageNode that is broken. DistanceDeformInside works for things that aren't images.
ImageNode on its own seems fine and does in fact distance-deform the sphere, albeit only within 0.005mm of the XY plane.
But an Extruded ImageNode doesn't do distance deformation.
And in fact even an Extruded Sketch doesn't do distance deformation. So the issue is with the new Extrude implementation based on half-spaces?
One clue is that the normals are glitchy along the sides of the extrusion. But the field cross-section looks fine?
As a sanity check I could try putting the old Exturde implementation back.
First observation is that the normals are glitchy with the old version as well. But DistanceDeformInside does work with the old version.
So why doesn't DistanceDeformInside work with the new version? Union,Intersection,Subtraction all work perfectly well.
OK, solved it! It's because DistanceDeformInside stashes a copy of its 2nd child, because the TreeRewriter only keeps track of the first child of modifier nodes. But DistanceDeformInside was taking a stashed copy of the plain version of its child, rather than of the "normalised" version, so it had a version that didn't actually generate a peptide expression. Fixed now.
And it looks like Claude's "4SED" is working pretty much perfectly. The only thing I don't like is that the "boundary" is 2 pixels wide, which means under linear interpolation it has nonzero thickness. I think I maybe want to add half a pixel to the distance on both sides?
Actually, on second thoughts... it isn't doing it properly at all! Instead of keeping reference to the coordinates of the nearest boundary pixel to each pixel, it is just tracking the direction, and adding it up with Manhattan distance. I've fixed it now.
So, good, I now have an algorithm for propagating distances in grids. Could probably use the same thing for VoxelNode, but I'll just leave a comment about it for now.
The stupid way to do text is to render it to a canvas and then import that as an image. (All those in favour??)
I guess do it that way for now and if I stumble across a better way in the future I can change it.
There is some risk of turning this into the first Isoform node type that actually depends on the browser. The rest
of the TreeNode
stuff is all "pure" I think. Never mind.
Let's try and get Cursor to do the bit that renders text to a canvas. Annoying parts include:
And then makeNormalised()
will just give you back an ImageNode for your canvas.
Nice, pretty much worked first try, just had the foreground and background inverted.
One issue is it always makes the text fit a 1mm by 1mm square, because that's how ImageNode presents the image.
Park this for now. "Good enough".
I'm probably not going to actually add gears today, but I wonder how hairy the SDF is?
It might be a case of making a 2d SDF that makes one tooth, and then PolarPattern'ing it to make all the teeth, and unioning with a circle to make the centre solid.
So what does a 2d SDF for one tooth look like?
Browsing https://www.shadertoy.com/results?query=gears it strikes me that most people don't know what gear teeth look like.
I tried getting Cursor to write me an SDF for an involute gear tooth, but it isn't working.
Without loss of generality, we have:
p.x = abs(p.x)
(mirror across y)Some info on https://www.drivetrainhub.com/notebooks/gears/geometry/Chapter%201%20-%20Involute.html
Apparently an involute curve is parameterised as:
x(t) = r * (cos(t) + t*sin(t))
y(t) = r * (sin(t) - t*cos(t))
So how do we work out t
? Or, rather, for some given point (x,y)
, x>=0
, y>=0
, how do we work out which is
the closest point on the curve?
Doesn't Matt Keeter have an example of a closed-form involute gear? I've definitely seen a demo somewhere of a closed-form involute gear, don't remember where.
This might help: https://github.com/mkeeter/antimony/blob/develop/examples/gear.sb
But I definitely remember seeing a picture of a gear or some gears.
Ah, it's on https://www.mattkeeter.com/projects/siggraph/
Implementation is in https://github.com/mkeeter/kokopelli/blob/master/examples/gear.ko
Well I gave the Kokopelli example to Cursor but it hasn't managed to make it work.
Remaining core problems: