  File: README.TXT for f_mandelbulb()
    By: David Wagner
  Date: 2009-12-18
Rights: (C)David Wagner, Licensed to be compatible with POV-Ray distribution.

There are two groups of POV-Ray Scene files.  Each pair of files is identical except for how the f_mandelbulb() function is defined.  


--- The User-defined SDL Function ---

Files starting with  "mbsdl_" #declare f_mandelbulb() as a recursive user-defined SDL function.  This usage is not valid SDL, but POV-Ray 3.6.1 and 3.7.0 beta 34 can (usually) render these scenes properly.  Except for mbsdl_standalone.pov, f_mandelbulb() is declared by including the file "mbsdl.inc".  You may make the SDL version of the mandelbulb function available in any scene by putting the following line at the top of your scene file.  Note msdl.inc must be in POV-Ray's search path.

   #include "mbsdl.inc"// Include this first.

WARNING: The recursive SDL function should be defined before anything else.

POV-Ray may crash if other things are #declared first.  Pleae do NOT report this to the POV-Ray team as a bug.  To my knowledge, recursive function calls are not supported in any official version of POV-Ray.  (Be happy it works at all.)


--- Modifying POV-Ray to add f_mandelbulb() Internally ---

The second set of files start with "mb_" and #declare f_mandelbulb() as an internal function compiled into a modified POV-Ray by applying the included patch to fnintern.cpp.  The patch (and the complete replacement file provided for convenience) are meant to be compiled into povray-3.7.0.beta.34.  A patch is also provided to add f_mandelbulb() to the functions declared in functions.inc.

As of this writing, you must also modify povray.h to extend the expiration date, and before compiling this modified version of POV-Ray, you must change line #128 of povray.h to include your name and email address.

WARNING: You must complete the DISTRIBUTION_MESSAGE_2 definition on line 128 of povray.h.

Once you have the modified executable compiled and working, you may declare the internal function the first place you need it.  The internal function appears to work about six times faster than the user-defined SDL function described in the previous section.

   #declare f_mandelbulb = function{internal(79)};

If you apply the patch to functions.inc, you may use the following line instead to include the rest of the internal functions along with f_mandelbulb().

   #include "functions.inc"


--- Using f_mandelbulb() ---

The function is declared in functions.inc like this.  The SDL version takes the same parameters.

#declare f_mandelbulb = function { internal(79) }
// Parameters: x, y, z
    // Five extra parameters required:
    // 1. Power to raise the radius
    // 2. Power to raise theta
    // 3. Power to raise phi
    // 4. Maximum number of iterations
    // 5. Assumed radius of divergence, usually 3.0

Please look at the example scene files to see how to use this function.

But, whichever way you declare the function, both versions of f_mandelbulb() should work the same (except for speed), and the function should work anywhere a function is allowed to be used in POV-Ray.  Some sample scenes are provided to get you started. 

mbsdl_standalone.pov and mb_standalone.pov are minimal files with no dependencies.

mbsdl.inc          This is the include file used by all of the mbsdl_* files below.

mbsdl_stage1.pov   mb_stage1.pov   Minimal files
mbsdl_basic.pov    mb_basic.pov    A mandelbulb isosurface colored by a 'bulb function
mbsdl_powers.pov   mb_powers.pov   Six mandelbulbs, powers 2-7
mbsdl_multi_p      mb_multi_p      Six composite power bulbs
mbsdl_pattern.pov  mb_pattern.pov  Use f_mandelbulb() as a pigment pattern
mbsdl_media.pov    mb_media.pov    Use f_mandelublb() as a media density

mbsdl_renderall.sh mb_renderall.sh Bash scripts to render them all. (Linux)


Try decreasing the max_gradient (a lot) for quicker isosurface rendering.  Also, try decreasing the iteration bailout used for the media and pattern examples if they are not fast enough for you.

There appears to be some "bad behavior" of f_mandelbulb() right at the radius of divergence, similar to the common coincident surface problem.  You may want to make your containing shape smaller than a sphere at the origin with a radius of three, especially when using this function as a media density.


--- Notes about this Function ---

This function differs from the usual mandelbulb algorithm in two important ways.

First, f_mandelbulb() returns a continuous value similar to the (inverse of the) usual Normalized Iteration Count Algorithm used for coloring the two-dimensional Mandelbrot set.  This is enormously helpful when visualizing an iteration surface.  The return value is inverted for three reasons.  This normalization "flips the function over" so the inside is defined correctly by POV-Ray, the numerical value of the surface of a given iteration remains the same regardless of the maximum iteration bailout, and the function value is usually normalized into the normal 0-1 range for POV-Ray functions.  Please note, however, that the return value may be greater than one outside the assumed divergence radius, that is, if your contained_by shape includes points further from the center of the 'bulb than r_bailout (the last parameter of the function, usually 3.).

Second, f_mandelbulb() takes three different "power" parameters.  'Bulbs made using differing values for two or more powers are, to the best of my knowledge, my original discovery, and is brand new fractal territory to explore.  Please have fun and share your findings.

To reproduce the behavior of the "standard" mandelbulb function, simply use the same value (p) for all three powers and the integer portion of the inverse of the return value, and ignore the deeper iteration values predicted by the smoothing function.

... function{min(1/int(f_mandelbulb(x,y,z,p,p,p,iteration_bailout,3)), iteration_bailout)}

(You may get a divide-by-zero error right at the origin.)

This will return the (integer) iteration count to assumed divergence.  It is generally more difficult (computationally) to define a smooth surface based on integral values.  Not only will most algorithms take longer to do this to a specified accuracy (because the gradient is infinite where the value changes), even after you find the location of the jump between two iteration values, it is also a challenge to then determine a reasonable surface normal at this point.

Also, as a bonus, this smoothing function returns reasonably accurate estimates of the location of the iteration surfaces one or more levels deeper than the iteration_bailout specified.  One of these levels is already "used" in the function definition to gain some speed by default, but feel free to try increasing the number of iterations to specify the isosurface threshold past the iteration_bailout you use in the function, especially if you are visualizing a deep surface.  (If you decrease the threshold too much, the surface can "dissolve" into blobs and tubes.)

Oh, and the power 2 mandelbulb appears to include points up to 3 units from the origin, so the assumed divergence radius is 3.


--- DOs ---

DO Decrease the size of your contained_by shape.

DO Reduce max_gradient to improve render times when previewing your scene.

DO Increase max_gradient and decrease accuracy for higher iterations and for final rendering.

DO Look at the max_gradient messages provided by POV-Ray after rendering a scene.

DO Experiment and post what you find.

DO Try a low anti-aliasing threshold for 'bulb media.  (I like: -J +A0.1 +AM2 +R2).


--- Don't ---

Do NOT report problems with this function to the POV-Ray development team as a bug.  Please post details of your difficulty to the appropriate POV-Ray newgroup.



--- Fractal Isosurface Tips and Tricks ---

I like to use the following command-line options for most isosurface renderings.  The reasons are explained below.

-J +A0.5 +AM2 +R2


1.  Don't iterate too much.

The smallest feature size, the grain size, of this fractal decreases rapidly with each iteration.  It usually doesn't take very many iterations for the surface convolutions to become much smaller than a single pixel, and both the appearance of your image and render times will suffer greatly if the fractal is iterated so the details are much smaller than the resolution available.


2.  Use low max_gradient and high iterations for previews.

Even the SDL version is reasonably snappy when you only need a low-quality preview of the image to lay out the scene or to check the color scheme of your 'bulb.  You may also want to decrease the number of iterations for layout; higher iterations will always be contained within the surface of a lower iteration.

3.  Make the contained_by shape smaller

Try to "cut out" just the portion of the 'bulb you are looking at.  This will help decrease the render time of your image without effecting the quality.


4.  Turn off Jitter

Unless you manage to keep the grain size on the order of the size of the pixels in your finished image, jitter can make parts of the image appear smeary or fuzzy.  (The command-line option to turn jitter off is -J.)


5.  Use recursive anti-aliasing.

POV-Ray's method 2 (recursive) anti-aliasing seems to give the best results with the least effort when rendering mandelbulbs.  Of course, your scenes may have different optimal settings, but I find a threshold around 0.5 to work well with a recursion depth of 2.  (The command-line options for this combination of anti-aliasing options is +A0.5 +AM2 +R2.)


6.  Use ambient 0

Unless you are using radiosity or a good coloring scheme, POV-Ray's ambient surface finish can destroy all the details in the shadowed regions made visible by setting a non-zero ambient.


7.  Provide depth cues

In part because of their incredible level of detail, and in part because of their alien nature, it can be difficult to convey the three-dimensional nature of these fractals in a two-dimensional image.  You may want to experiment with fading light sources, atmospheric fog, media, focal blur, and other techniques to give your image a better sense of depth.  Even including other, more familiar objects on and around your 'bulb may help the viewer get an idea of the overall shape of the fractal in view.

8.  Have fun!

---David Wagner