Addendum: Organic Modeling with Pure Mathematics
Addendum: Organic Modeling with Pure Mathematics
OpenSCAD’s geometric primitives (cubes, cylinders, spheres) are powerful for mechanical parts. But organic forms — a human figure, a horse, a gaunt knight’s face — require a different mathematical approach. No GUI sculpting tools. No Blender. Just equations.
The Core Technique: hull() as Organic Blending
hull() computes the convex hull of its children — the tightest skin that wraps around all shapes inside it. Place two spheres of different sizes and hull() them: you get a smooth taper. That’s a limb. A torso. A neck.
// A tapered limb — two spheres, hull blends between them
module limb(length, r_top, r_bottom) {
hull() {
sphere(r=r_top, $fn=48);
translate([0, 0, length])
sphere(r=r_bottom, $fn=48);
}
}
// Thick shoulder tapering to thin wrist
limb(length=30, r_top=4, r_bottom=1.5);
| Operation | Math Concept |
|---|---|
|
Convex hull — computational geometry. The minimal convex set containing all input points. |
Varying |
Parametric tapering — linear interpolation between radii across a length. |
|
Polygon approximation of curves. Higher |
Ellipsoids: Stretching the Sphere Equation
A sphere is x² + y² + z² = r². An ellipsoid stretches each axis independently: (x/a)² + (y/b)² + (z/c)² = 1. In OpenSCAD, scale() on a sphere produces an ellipsoid.
// A gaunt, narrow head — stretched vertically, compressed laterally
module gaunt_head() {
scale([0.7, 0.8, 1.3])
sphere(r=6, $fn=128);
}
// A barrel chest — wide, shallow, short
module torso() {
scale([1.0, 0.6, 1.8])
sphere(r=8, $fn=64);
}
This is direct manipulation of the ellipsoid equation through scale factors.
Building a Figure: El Caballero de la Triste Figura
A complete stylized Don Quijote — every line is a math operation:
// El Ingenioso Hidalgo Don Quijote de la Mancha
// El Caballero de la Triste Figura — on Rocinante
// Pure geometry — no mesh imports, no sculpting
module limb(length, r_top, r_bottom) {
hull() {
sphere(r=r_top, $fn=48);
translate([0, 0, length])
sphere(r=r_bottom, $fn=48);
}
}
module quijote() {
// Head — gaunt, elongated (ellipsoid)
translate([0, 0, 95])
scale([0.7, 0.8, 1.3])
sphere(r=5, $fn=128);
// Neck — thin
translate([0, 0, 85])
limb(10, 2.5, 1.8);
// Torso — tall and thin (the sad knight is skin and bone)
translate([0, 0, 50])
scale([0.5, 0.4, 1.0])
cylinder(h=35, r=8, $fn=64);
// Right arm — lance arm, extended forward
translate([6, 0, 75])
rotate([70, 0, 10])
limb(28, 2.0, 1.0);
// Left arm — shield arm, bent
translate([-6, 0, 75])
rotate([30, 0, -15])
limb(22, 2.0, 1.2);
// Lance — long, thin, angled forward
translate([8, 0, 78])
rotate([75, 0, 10])
cylinder(h=70, r=0.4, $fn=16);
// Legs
translate([3, 0, 50])
rotate([180, 0, 0])
limb(40, 3.0, 1.5);
translate([-3, 0, 50])
rotate([180, 0, 0])
limb(40, 3.0, 1.5);
// Base — so it stands
translate([0, 0, -2])
cylinder(h=2, r=15, $fn=64);
}
module rocinante() {
// Body — thin, sad horse
hull() {
sphere(r=7, $fn=48);
translate([25, 0, 0])
sphere(r=5, $fn=48);
}
// Neck — drooping forward
translate([28, 0, 3])
rotate([0, 30, 0])
limb(18, 4, 2.5);
// Head — long equine face
translate([38, 0, 16])
rotate([0, 60, 0])
scale([1, 0.6, 0.5])
limb(12, 2.5, 1.5);
// Legs — four thin, tired legs
for (x = [-4, 4, 18, 22])
translate([x, 0, -3])
rotate([180, 0, 0])
limb(25, 2.0, 1.2);
// Tail — drooping
translate([-5, 0, 2])
rotate([0, -50, 0])
limb(15, 1.5, 0.3);
}
// Compose the scene
translate([0, 0, 35]) quijote();
translate([-15, 0, 30]) rocinante();
The Mathematics of Organic Form
| Technique | Math | What It Creates |
|---|---|---|
|
Convex hull of point sets |
Smooth tapered limbs |
|
Ellipsoid equation: (x/a)² + (y/b)² + (z/c)² = 1 |
Gaunt faces, barrel chests, horse bodies |
|
3D rotation matrices (Euler angles) |
Arm positions, lance angle, drooping neck |
|
Iterating over vector arrays |
Four legs from one definition |
Nested |
Composition of affine transformations |
Articulated figures from simple primitives |
|
Polygon count ↔ curve smoothness trade-off |
Fine detail on faces, coarse on hidden geometry |
Signed Distance Functions (SDF) — Advanced
For truly organic forms beyond what hull() can achieve, the mathematical frontier is Signed Distance Functions. An SDF defines a shape as a field: every point in space has a value — negative inside, positive outside, zero on the surface.
A sphere SDF: f(x,y,z) = sqrt(x² + y² + z²) - r
Combine shapes with pure math:
| Operation | Function | Result |
|---|---|---|
Union |
|
Two shapes merged |
Intersection |
|
Only the overlap |
Subtraction |
|
Cut one from another |
Smooth blend |
|
Organic blending — like muscle meeting bone |
The smooth blend formula is the key — it creates the soft transitions that make organic shapes look alive. The parameter h controls how much the shapes melt into each other. This is calculus: the blending function is a C¹-continuous approximation of the min function.
Tools that speak SDF natively:
-
libfive — C/C++ SDF engine with a Guile (Scheme) scripting interface
-
ImplicitCAD — Haskell-based, OpenSCAD-like syntax but uses implicit surfaces internally
-
Pure Python + numpy-stl — write SDF functions in Python, marching-cubes to mesh, export STL. Full control, no dependencies beyond NumPy and SciPy
Project Roadmap: From Primitives to Sculpture
Level 1: OpenSCAD primitives → cubes, spheres, cylinders Level 2: hull() blending → organic limbs, tapered forms Level 3: Ellipsoid composition → figures, animals, characters Level 4: SDF smooth blending → muscle, flowing robes, facial features Level 5: Python + marching cubes → any shape defined by any equation
Each level is a semester of math disguised as art. By level 3, your kids are doing linear algebra. By level 5, they’re doing multivariable calculus — and they think they’re making toys.