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

This set of files should help you to set up POV-Ray to render variations of the mandelbulb, a three-dimensional analogue to the Mandelbrot set.  The function is defined both in POV-Ray's scene description language for use in any fairly recent version of the program, and in C++ suitable for creating a patched version of POV-Ray 3.7 beta 34.

In addition, some very basic POV-Ray scene files demonstrate how to use the f_mandelbulb() function. 


--- 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.  The file "mbsdl_standalone.pov" contains everything needed to render a mandelbulb in a singe scene file, while "mbsdl.inc" is intended to be included in your own scenes.

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

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

POV-Ray may crash if other things are #declared first.  Please 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.)


--- Sample Scene Files ---

POV-Ray scene files starting with "mb_" (except mb_standalone.pov) have a block of code at the top intended to automatically switch between using the SDL function and using an internal function you have compiled into the program.  This code simply checks whether "mbsdl.inc" is available, and if it is not, POV-Ray will attempt to use the internal function in a modified version of the program.

The scene "mb_standalone.pov" does not include this check and will only work if the internal f_mandelbulb() function is present.


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

To compile f_mandelbulb() into POV-Ray, apply 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 instead use the following line to include the rest of the internal functions along with f_mandelbulb().

   #include "functions.inc"

Don't forget to rename or remove "mbsdl.inc" so the sample scene files cannot find it and will use the internal function instead.


--- 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
    // Six extra parameters required:
    // 1. Power to raise the radius
    // 2. Power to raise theta
    // 3. Power to raise phi
    // 4. Phase shift of phi
    //    When all three powers are the same,
    //    this function is equivalent to the
    //    consistent formula when the phase is 0, the
    //    Cosine Variation when -pi/2, and the
    //    original formula when  pi.
    // 5. Maximum number of iterations
    // 6. 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  Minimal SDL function scene with no dependencies.

mbsdl.inc             This is the include file for use with an unmodified POV-Ray.

mb_stage1.pov         A minimal file that checks for the SDL include file.
mb_basic.pov          A mandelbulb isosurface colored by a 'bulb function
mb_powers.pov         Six mandelbulbs, powers 2-7
mb_variations.pov     The four main variations of the power 8 mandelbulb.
mb_multi_p.pov        Six composite power bulbs
mb_pattern.pov        Uses f_mandelbulb() as a pigment pattern
mb_media.pov          Uses f_mandelbulb() as a media density

mb_standalone.pov     Minimal internal function scene file.

mb_renderall.sh       Bash script to render them all. (Linux)

Try decreasing the max_gradient (a lot) for faster 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, especially when using this function as a media density.  If you have this problem, try shrinking the contained_by shape or increasing the assumed radius of divergence.


--- Notes about this Function ---

This function differs from the usual mandelbulb algorithm in three 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, an additional phase parameter, first described by Paul Nylander, allows you to duplicate four variations of the mandelbulb power function along with functions smoothly in-between these variations.  The most popular variations are the "Cosine Variation" with a phase of -pi/2, the consistent variation with phase zero, and the original mandelbulb function with a phase of pi.  The fourth variation with a phase of pi/2 seems to be less popular.  

Third, f_mandelbulb() takes three different "power" parameters, allowing for a stunning variety of 'bulbs.  This is mostly brand new fractal territory to explore.  Please have fun and share your findings.

To reproduce the behavior of the "standard" mandelbulb functions, 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(int(1/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.)  However, to avoid this dissolution when rendering an isosurface of a fractional iteration less than five or six, call the mandelbulb function with int(iteration_bailout + 0.5) so it rounds properly.

Oh, and the power 2 mandelbulb appears to include points up to 3 units from the origin, so the assumed divergence radius is usually 3.  Increasing this improves the accuracy of the smoothing function, and this can be helpful when attempting to smoothly vary the iteration surface visualized since there can be some jaggedness at integral iteration surfaces. 


--- 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 newsgroup.



--- 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.  Also, try using isosurface max_gradient evaluate to reduce the time it takes to trace through the empty parts of the contained_by shape.


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