I have to admit that when generating isosurfaces, I’ve come to prefer polynomial-trigonometric functions over noise arrays. Where noise gives samey-looking blobs in all directions, PTFs (polytrigs?) provide structure and asymmetry at low cost.
Here’s the source function I used to generate those surfaces.
var k1 = M.rng.get(-1, 1);
var k2 = M.rng.get(-1, 1);
var k3 = M.rng.get(-1, 1);
var source = function(x, y, z) {
if (y < 0.1)
return -1;
var a = x + y + k1;
var b = y + z + k2;
var c = z + x + k3;
var d = a + b * c;
var e = a * b + c;
return Math.cos(a * d + b * d + c);
};
Rolling up a few random offsets gives us a variety of surfaces. The specifics of the math don’t matter: I just want a polynomial that’s complex enough to be interesting. We take the cosine to smooth the results and limit them to the range (-1, 1).
For the field function, I’ve dropped the cube-based point field thingy I used in the last couple of posts in favor of a modified 3D interpolator.
var field = function(x, y, z) {
function lerp(y0, y1, mu) {
return mu * y1 + (1 - mu) * y0;
}
var xi0 = Math.floor(x);
var mux = x - xi0;
var yi0 = Math.floor(y);
var muy = y - yi0;
var zi0 = Math.floor(z);
var muz = z - zi0;
var xi1 = xi0 + 1;
var yi1 = yi0 + 1;
var zi1 = zi0 + 1;
var i1, i2, i3, i4;
i1 = lerp(source(xi0, yi0, zi0), source(xi0, yi0, zi1), muz);
i2 = lerp(source(xi0, yi1, zi0), source(xi0, yi1, zi1), muz);
i3 = lerp(i1, i2, muy);
i1 = lerp(source(xi1, yi0, zi0), source(xi1, yi0, zi1), muz);
i2 = lerp(source(xi1, yi1, zi0), source(xi1, yi1, zi1), muz);
i4 = lerp(i1, i2, muy);
return lerp(i3, i4, mux);
};
It’s a stripped-down version of the code I use to generate isosurfaces from noise arrays. It uses linear rather than cosine interpolation. Initially, I made the change to improve its performance, but found that it also allowed a greater variety of shapes.

