SDF CAD

Check it out here

SDF's are pretty neat!, A function generated from simple mathematical functions but can make some really complex geometry. If you want to see some really beautiful examples go no furthur than shadertoy.com. Would you believe the following scene was not made in some complicated software with hundreds and thousands of menus and buttons backed multi billion dollar corporation, but its just some 400 lines of C like code typed into an editor. Its even animated !. Inigo Quilez who runs the website, is a well known personality in the graphics space and has some really well put explanations on how SDF's work (link here).

I wont go into detail how SDF's work. The gist is that its a way to represent the "distance" to a surface of an "object". Its a function that when evaluated at some point in space will tell you how far the nearest surface to the object is. On the surface of the object the sdf value ofcourse is 0. Thats it, its easy and known how to construct SDF's for some primitive objects like spheres, cubes, cones, cylinders, prisms etc. Theres a way to combine them by putting them through another function. You can take intersections and subtract one object from another. Rotate, move, elongate, scale lot of great stuff!. Whats neat is that you can also round the corners and edges very trivially in this representation. When combining two objects you can smoothly combine them too ! (figure below). NEAT!. Rendering them is a matter of doing a thing called raymarching, fairly simple to generate shadows and lighting. I think anyone who's even slightly mathematically inclined is mindblown when first coming across SDF's and shadertoy. You really should check it out if you haven't.

As a 3Dprinting nerd one of the first things this got me thinking was what if this was a way to design objects for 3D printing. I'm not the first to think of this, there's a dozen of implementations of SDF's for generating models out there (sdfx, fogleman/sdf). I wrote a simple tool with 3 key features. The language of "drawing" is Python. It runs in your browser (pyodide) and can be viewed in the browser (sdfx and sdf.py dont have a viewer). You can generate STL's (marching cubes) for 3d printing. Almost all the primitives from Inigo Quilez (link here) are supported. Combining objects with unions, intersections , subtractions and there respetive smoothened versions are there. Scaling, elongate, rotation , translation, even twisting and bending!. All with Python!, All in your browser!.

How does this work? You type your python code in the editor. The browser runs the code in pyodide (a python implementation running in WASM) which generates a sort of tree of the objects that you added to the scene. When you hit recompile it recursively goes throught the tree generating and SDF of your scene in glsl. The shader is then raymarched to show you what it looks like. GenerateSTL first evalutates the SDF at gridpoints and stores them in a framebuffer to be returned to JS, then uses marching cubes on these points generate a mesh and export as STL, for this i used the marching-cubes-fast library.

While the SDF's listed on this page assume you can pass functions around, thats not true in glsl. Hence at such transforms we introduce a block scope and compute what the function would do, essentially inlining it. Every gen_glsl method of an Object takes two parameters , pcoord and target_var. The gen_glsl then might introduce a new block {} where it does some computation or for primitive objects just compute the sdf (target_var = sphere(pcoord,...)). The final result of this computation is stored in target_var. Depending on the type of Object this involves computing new temporary coordinates from the passed in pcoord (for rotation, translation, elongation etc), evaluating its childrens gen_glsl on the transformed pcoord, storing the childrens gen_glsl into a temporary target to be accumulated into the passed down target_var etc (for ex for union). The leaves of the tree are the primitive objects like Sphere which have no children it simply evaluates its respective sdf. The primitives are defined in pre.frag.

The STL generation needs more work to be done, right now its generating points by evaluating the sdf on a grid and saving to a 3d texture , this is unfeasable for high resolution due to limited VRAM, The default resolution is kept to 128 points on a cube of -5 to +5 in all dimensions.

I hope you have fun with it.