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);
Table 1. Math behind it
Operation Math Concept

hull() of two spheres

Convex hull — computational geometry. The minimal convex set containing all input points.

Varying r values

Parametric tapering — linear interpolation between radii across a length.

$fn=48

Polygon approximation of curves. Higher $fn = more vertices = smoother surface = longer render.

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

hull() of 2 spheres

Convex hull of point sets

Smooth tapered limbs

scale([a,b,c]) on sphere

Ellipsoid equation: (x/a)² + (y/b)² + (z/c)² = 1

Gaunt faces, barrel chests, horse bodies

rotate([x,y,z]) on limbs

3D rotation matrices (Euler angles)

Arm positions, lance angle, drooping neck

for loop with positions

Iterating over vector arrays

Four legs from one definition

Nested translate(rotate(hull()))

Composition of affine transformations

Articulated figures from simple primitives

$fn variation

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

min(shape_a, shape_b)

Two shapes merged

Intersection

max(shape_a, shape_b)

Only the overlap

Subtraction

max(shape_a, -shape_b)

Cut one from another

Smooth blend

min(a,b) - h²×max(h-abs(a-b), 0) / (4×h)

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.