# spherical

## Spherical Functions as Voxels

- Intro
- Cartesian Functions
- Spherical Functions (this post)
- Curve functions

To convert spherical functions into a voxel volume is a bit, but not much, more coplicated than for Cartesian functions.

In the case of Cartesian functions the key criterion was the height above the *x*-*y* plane. In the case of a spherical function, it’s the distance from the centre point of the function that we’ll need to perform the comparison on.

We define our spherical functions using angles *θ* and *φ* circumlocating this point. The angle *θ* represents the angle around the *z*-axis through the centre point of the object. The angle *φ* represents the elevation above the *x*-*y* plane also through the centre.

Converting to a triangulation involves stepping through *θ* and *φ* with a given step distance and calculating the radius *r* = *f*(*θ*, *φ*) for the function. This radius acts like a spine emerging from the centre at the given angle and with length *r* as defined by the function. These spines are used to define the vertices of the triangles that form the surface of the object.

When voxelating the volume, the question becomes one of whether a given voxel, defined by its (*x*, *y*, *z*) position, is inside or outside the object. We do this by considering the spine that runs between the voxel co-ordinates and the centre of the object, and calculating the *θ* and *φ* values that would apply in this case.

The contrasting nature of the two approaches shows itself here. To create triangles you have to calculate the (*x*, *y*, *z*) position of a triangle vertex from the *θ* and *φ* values. In both cases the *θ* and *φ* are needed to calculate the radius.

Calculating *θ* (rotation) and *φ* (elevation) values isn’t hard with a bit of trigonometry.

*θ* = tan^{-1} (*y* / *x*)

and

*φ* = tan^{-1} (*z* / (*x*^{2} + *y*^{2})^{1/2})

Here’s the code we use to do this.

fZFunc = psFuncData->fZMin + (nSlice * fZStep); for (nX = 0; nX < nResolution; nX++) { fXFunc = psFuncData->fXMin + (nX * fXStep); for (nY = 0; nY < nResolution; nY++) { fYFunc = psFuncData->fYMin + (nY * fYStep); // Calculate the angles fOpposite = (fXFunc - psSphericalData->fXCentre); fAdjacent = (fYFunc - psSphericalData->fYCentre); fElevation = (fZFunc - psSphericalData->fZCentre); fAFunc = atan2 (fOpposite, fAdjacent); fDiag = sqrt ((fAdjacent * fAdjacent) + (fOpposite * fOpposite)); fPFunc = atan2 (fElevation, fDiag); if (psSphericalData->psVariableA) { SetVariable (psSphericalData->psVariableA, fAFunc); } if (psSphericalData->psVariableP) { SetVariable (psSphericalData->psVariableP, fPFunc); } fRFunc = ApproximateOperation (psFuncData->psFunction); fDistance = sqrt ((fAdjacent * fAdjacent) + (fOpposite * fOpposite) + (fElevation * fElevation)); if ((fDistance < fRFunc) && ((psFuncData->boMaterialFill == TRUE) || (fDistance > (fRFunc - psFuncData->fMaterialThickness)))) { ucFill = 255u; } else { ucFill = 0u; } } }

Once we have them, we can plug them into the function that defines our spherical object to calculate the radius at that point *r*‘ = *f*(*θ*, *φ*). We compare this with *r*, the length of the spine from the centre of the object to the position of our voxel.

*r* = (*x*^{2} + *y*^{2} + *z*^{2})^{1/2}.

Notice we’re pretending here the co-ordinates of our object are at the origin. If they aren’t, we need to subtract the centre co-ordinates component-wise from our voxel co-ordinates first.

The comparison is then simply *r* ≤ *r*‘ if we’re inside the object and *r* > *r*‘ if we’re outside.

We perform these calculations and comparison for each voxel in our voxel space. As before, if we’re inside we set the voxel to be filled, otherwise we leave it empty.

That deals with Cartesian and spherical functions, which are the easy ones, because the mapping between voxels and the co-ordinate system is one-to-one. Sadly this isn’t the case for curve functions, which I’ll tackle in the next post.

## Voxel Volumes

One of the main feature additions of the latests version of Functy has been the ability to export as SVX files. Functy could already export in PLY and STL, but both of these are triangle based. They represent the 3D functions as surfaces defined by carefully aligned triangle meshes. Rendering objects using a graphics card also uses the same triangulation process, so exporting as PLY or STL is a very natural extension of the existing rendering.

The SVX format is different though. It stores the models as a voxel image (a voxel being a three dimensional pixel, for those who didn’t grow up through the 90s demo scene). As a result, SVX doesn’t just store the surface, but also the volume of a function.

Turning a triangulated surface into a voxelated volume isn’t necessarily straightforward, but Functy has the advantage of having all its objects originate as purely mathematical forms. In theory, this means voxel rendering them as volumes should be quite easily.

What I found in practice is that for Cartesian functions and spherical functions this is true: they can be turned into voxel volumes in a very natural way. Curve functions are a different story though. In the next few posts I’ll go through each of the processes separately, to give an idea about how the solutions for each of the three function types were coded.

- Intro (this post)
- Cartesian Functions
- Spherical Functions
- Curve functions

## Projections

The sun was out in Liverpool today, creating crisp and long evening shadows. So it seemed like a great opportunity to take photos of recent 3D printed Functy objects. The full images are rather large, but show the grain of the printing, which I think is rather interesting in itself. Click on the images for the full views.

The original Lissajous is up on deviantArt and Shapeways; the alien egg is also on deviantArt and Shapeways.

## Comparing renders with reality

Shapeways delivered a new batch of 3D prints recently. I was particularly pleased with the Alien Egg print of a spherical function with the formula:

radius = (3*(0.5+(sin(cos(a)+(p*((3+cos((pi*0.3)-1.5))/4))*10)**2)+((6/6.6)*((2+sin(8*a))/3)**4)))*sin(p)+(4.3*(1-(sin(p)**2))),

colour (R, G, B) = (r/8, (3+sin((a)*8))/5, (3+cos(a*8))/5).

The print is actually rather small (just 6 cm diameter) and the ridges of the shape are really quite delicate. In spite of this, the 3D print has come out really very similar to the original design. I guess you might expect it to be pretty similar, given the way it was produced directly from the model! However, if you look really closely at the original you can see the strata through the object created by the printing process. What I’m really impressed with, though, is the colour produced. I’d expected this to be a bit washed out, but in practice it’s a pretty impressive match.

Below is a comparison of (from top to bottom) the Functy render, the 3D print and a render done using Blender Cycles. In case you’re interested and your browser supports APNGs, there’s also a peculiar animated version!

## Network structures

As part of an experimental game project I’ve been trying to use the Functy rendering routines to visualise network structures. At the moment it’s at a very early stage, but has - I think - already generated some interesting results.

The screenshot below shows a network of 60 nodes, each one rendered as a spherical co-ordinate function, joined together using links rendered as curves. I just plucked some simple functions out of the air to see what the results would be like but am hoping to extend it with more interesting shapes as things progress.

The various parts of the network are a little hard to discern with a static image, but when I tried to capture a video the result was a mess of fuzzy artefacts (I think there must be something going wrong with my screen capture software), so I gave up on that.

The next step, after neatening up the code, is to arrange better animation of the nodes and links, with dynamic movement based on things like the forces between the nodes. I’m hoping this will produce some really nice effects, and if anything comes of it I’ll put a bit more effort into getting a successful video capture.

## Functions in the real world

This afternoon a very exciting (at least for me!) parcel arrived all the way from Eindhoven in the Netherlands. The first ever ‘real’ 3D function generated using Functy and printed by Shapeways using a 3D printer.

I’m really pleased with the results. Shapeways were not only able to print out the rather convoluted function in 3D, but they also printed it in full colour too.

Here’s a screenshot and some photos of the final result.

The colouring is really great - much more vivid than I’d expected - and it’s not as delicate as I’d feared (it survived the journey through the post, at any rate!). This is a spherical function, which is the easiest to print (they generate meshes without holes automatically, which are needed for 3D printing). Hopefully the next step will be to attempt a parametric curve print.

If you want to play around with the model yourself, you can download the Functy definition file, or if you’re feeling flush, order your own 3D printed version from Shapeways. Such is the beauty of 3D printing!