Approximation Macro

© Mike Williams 2003, 2004

Up | Previous: Param.inc | Next: New Stuff | Alphabetical Index

Kevin Loney's Approximation Macro

Kevin Loney has produced an include file which produces a mesh object that approximates an isosurface. This technique produces object which renders faster than real isosurfaces, but usually takes much longer to parse.

Kevin's isosurface.inc can be found on Kevin's webpage.

The mesh data can be written to a file, so it need only be parsed once making it faster to re-render the scene or to have more than one copy of the surface in a scene.

In the vast majority of cases, the total time required to parse and render the approximation is greater than the time taken to render a real isosurface, but there could well be situations where using the approximation could be faster, for example if the same isosurface were to appear in each frame of an animation it would only need to be parsed once and then the data could be read from the file for all the subsequent frames. This might be useful for Mechsim animations - the real isosurface would be used for the simulation calculations, but the approximation could be used for the actual rendering.

The top image was created as a POV 3.5 isosurface.

The second image was created as an approximation.

The third image shows how the approximation is constructed from a mesh of triangles.

The last image shows the same approximation but with a mesh of flat triangles instead of smooth_triangles

The syntax of the POV 3.5 isosurface is:


#declare f = function {f_torus(x,y,z,1,0.4)}
#declare isoMin = <-R,-R,-R>
#declare isoMax = <R,R,R>
  isosurface {
    function { f(x,y,z)}
    max_gradient 1.1
    contained_by{box {isoMin,isoMax}} open
  }
The syntax for the approximation is:

#declare f = function {f_torus(x,y,z,1,0.4)}
#declare isoMin = <-R,-R,-R>
#declare isoMax = <R,R,R>
#declare isoSmooth = yes;
#declare isoSegs = <15, 15, 15>
#declare isoFileOption = 1;
#declare isoFile = "KL01.iso";
#declare isoName = "Surface";
#include "isosurface.inc"
  object { Surface }
The possible parameters for the macro are:-
  • f() The isosurface function.
  • isoMin and isoMax The corners of the bounding box. If not supplied, the unit cube <-1,-1,-1><1,1,1> is used.
  • isoSegs The number of segments to be used in the x, y and z directions. If not supplied, <10,10,10> is used. Higher values give better approximations, but take longer to parse.
  • isoFileOption Set this to 1 to generate the approximation and store the mesh in a file. Set it to 0 to read the data from a previously generated file. Set it to 2 to generate the approximation but not store the data in a file, in which case the syntax for using the mesh is slightly different as the result is an inline mesh rather than being #declared.
  • isoFile The name of the file for the mesh data.
  • isoName The name to be used for the generated mesh.
  • isoSmooth Set this true for a smooth_triangle mesh. Set it false for unsmooth triangles. If not supplied, the triangles will be unsmoothed, as shown in the fourth image.
  • isoThreshold The value for the "threshold" parameter of the isosurface. If not supplied, the threshold is set to 0.
  • isoNormalAccuracy This controls the Gradient Function Accuracy used for vector analysis operations called from "math.inc" which are used for calculating the normals for smooth_triangles. In most cases, this value has no noticeable effect on the quality of the image or on the time taken.

The result is returned as a mesh which is #declared with the name that you specified in isoName, except when isoFileOption is set to 2, in which case the mesh is actioned immediately rather than being #declared.

The syntax when using isoFileOption = 2 is like this:


#declare f = function {f_torus(x,y,z,1,0.4)}
#declare isoMin = <-R,-R,-R>
#declare isoMax = <R,R,R>
#declare isoSmooth = yes;
#declare isoSegs = <15, 15, 15>
#declare isoFileOption = 2;
object {
  #include "isosurface.inc"
  pigment {rgb 1}
}
There is now also a modified version of this macro by Jaap Frank, which runs nearly twice as fast.
The parameters for the Jaap Frank version of the macro are slightly different in that the isosurface function is called Fn() instead of f().

In the lastest version of the macro there's an additional Depth parameter. The macro performs surface subdivision on cells which contain part of the surface, and skips cells which don't.

For example, rendering this example file without subdivision, like this


#declare isoSegs = <32, 32, 32>
#declare Depth = 0;
causes the macro to examine all 32768 cells (32*32*32), but only 2664 of those cells contain parts of the surface.

Rendering the example with one level of subdivision, like this


#declare isoSegs = <16, 16, 16>
#declare Depth = 1;
causes the macro to examine 4096 cells at the initial depth, and find that only 720 of them contain parts of the surface. It then subdivides each of these 720 cells into 8 subcells and examines them and finds that 2664 of the subcells contain parts of the surface. It renders the same 2664 surface fragments as before, but it only needed to examine 9856 cells in order to find them (4096 + 720*8) instead of 32768.

Don't forget to change your isoSegs to smaller values when using subdivision, and be aware that the default Depth value is 2.

All the other parameters are the same as the Kevin Loney version.


Download a zip file containing the POV source files associated with the images on this page.

Up | Previous: Param.inc Next: New Stuff | Alphabetical Index