New Stuff

© Mike Williams 2002,2003,2004,2005

Up | Previous: Approximation Macro | Next: Parametric spline functions | Alphabetical Index

User functions with parameters

It is now possible to declare user functions that have extra parameters.

  #declare Gravity_Well =
     function(x,y,z,Strength) {
         x*x -Strength/y*y +z*z
     }
declares a function that takes an extra "Strength" parameter. We don't tell the function what the value of "Strength" is when we declare it, but only when we reference it

  isosurface {
    function { Gravity_Well(x, y, z, 0.002) }

#declare S = function {
   spline {
     linear_spline
    -1.0, < 0.5, 0, 0>,
    -0.5, < 0,   0, 0>,
     0.01,< 0.2, 0, 0>,
     0.5, <-0.2, 0, 0>,
     1, <-0.2, 0, 0>
   }
 }

isosurface {
  function { y - S(x).x }

Spline Functions

It is now possible to use a spline function to generate an isosurface.

In this case I'm using the first column of the spline only. As x goes from -1 to +1 S(x) goes from <0.5,0,0> to <-0.2,0,0> along the spline.
For an isosurface, we don't want a vector function, so we choose the S(x).x component of the function.

We can see that the isosurface follows the x co-ordinate of the spline, which is shown in red in the attached image.

Warning: There are known bugs in spline functions in POV 3.5b1. For example, if we replace the 0.01 point in the above example by

    0.0, < 0.2, 0, 0>,
the spline behaves in an unexpected manner.

#declare S = function {
   spline {
     natural_spline
      -1, < 0.5, 0, 0.0>,
    -0.5, < 0.2, 0, 0.4>,
    0.01, < 0.2, 0, 0.2>,
     0.5, < 0.4, 0, 0.4>,
       1, < 0.0, 0,-0.6>
   }
 }

isosurface {
  function { y - S(x).x - S(z).z }
But we're not restricted to using just one dimension of the spline, or to using linear splines.

Here's a natural spline function. We can see that the surface follows both the x and z co-ordinates of the spline, which are shown in red and green respectively in the attached image.

In this way, it's possible to generate a 3d isosurface sheet from two 2d splines.

The new POV 3.5 "cubic_spline" is not very suitable for isosurface work because it can be undefined at the endpoints, which causes strange effects in the surface.

Another thing that we can do with spline functions is to sweep along a 3d spline, in a similar manner to a sphere_sweep.

#declare S = function {
   spline {
     natural_spline
      -1, < 0, 0.5, 0.0>,
    -0.5, < 0, 0.2, 0.4>,
    0.01, < 0, 0.2, 0.2>,
     0.5, < 0, 0.4, 0.4>,
       1, < 0, 0.0,-0.6>
   }
 }

isosurface {
  function { pow(y - S(x).y),2) 
       + pow(z - S(x).z,2) - 0.05 }
What you get isn't exactly the same as a sphere_sweep, it's more like a "hoop sweep" with the hoop always oriented in the same direction rather than turning as the spline turns.

It's also possible to write it in a way that more clearly separates the "hoop" function from the spline function, making it easier to replace the circular hoop with some other shape.


#declare Hoop = function(x,y,z,r){y*y + z*z - r*r}

isosurface {
  function {Hoop(x, y-S(x).y, z-S(x).z, 0.223)}
In the upper image, I've made the isosurface slightly transparent and indicated the path of the spline itself in yellow.

In the lower image I've added a ripple to the isosurface, so now you can drape intestines along a 3d spline path.


parametric {
  function {S(u).x + sin(v)}
  function {S(u).y + cos(v)}
  function {S(u).z}
    <0,-pi><17,pi>
  contained_by{box
     {min_extent(The_Path)-<1,1,0.1>
      max_extent(The_Path)+<1,1,0.1>}
     }

But that previous technique doesn't work with splines that have loops in them. The problem is that we were using the spline control points as our x co-ordinate and expressing y and z in terms of that x. The sequence of control points can't loop back on itself.

The way to follow 3d splines that contain loops is to use all three of the spline dimensions to specify the path of the spline, and express x, y, and z in terms of a fourth variable, call it "u", which follows the control points.

So what we need is a parametric isosurface.

In this case "u" follows the spline control points, and x, y, z are expressed in terms of u like S(u).x, S(u).y, S(u).z. On its own that would give an infinitely thin string that follows the spline path. We can fatten it out by adding some terms in a second variable "v" which describe how far the surface is from the path.

Once again I have made the isosurface transparent and drawn the actual spline path inside it in yellow.

For this image, I didn't know how large to make the contained_by box, so I've calculated it during the parsing of the scene by taking the min_extent() and max_extent() vectors of the yellow spline path and added something to allow for the thickness of the wrapping.

You may have noticed that in the previous examples, the swept shape always faces in the same direction. In the attached zip file I've included the SweepSpline macro that sweeps a shape in such a way that it turns to always be perpendicular to the spline that it is being swept along.

It's not actually an isosurface at all, but a mesh. I just stuck it here since it's doing a similar job to some of the isosurface examples on this page.


Download a zip file containing the POV source files for all the images that appear on this page.

Up | Previous: Approximation Macro | Next: Parametric spline functions | Alphabetical Index