POVRAY III: Design of Recursive Structures

ArticleCategory: [Choose a category for your article]


AuthorImage:[Here we need a little image from you]

[Photo of the Author]

TranslationInfo:[Author and translation history]

original in es Antonio Castro 

es to en Miguel A Sepulveda

AboutTheAuthor:[A small biography about the author]

Computer Science is my profession and also part of my free time. I like to share my hobby, as everyone probably does. I admit it! I am one of those strange characters who dislikes windoze, at least MSDOS has the category of a toy that is least pretentious of its capabilities and does not fill your computer of numerous files that where you never now if they are useful and what they are good for.

Abstract:[Here you write a little summary]

This time we explore how to design recursive structures with Povray and how to create beautiful images with this technique.

ArticleIllustration:[This is the title picture for your article]


ArticleBody:[The article body]

Art and Tecnique in computer science.

Our series of articles touches technical and non-technical aspects of POVRAY. Technology is important, we already mentioned it several times, but it is even more important to learn to take advantage of its possibilities in an artistic and creative environment. The computer science is so unlike any other discipline that perhaps for some it might be the perfect environment to express his or her artistic qualities. We cannot abandon the process of learning about technology because it is a necessary step, however in my personal experience technology is only an instrument that helps us to achieve a new form of communication.

In my articles I try to mix cold technical knowledge with issues purely creative or artistic. My goal is to put forward ideas, examples that can trigger the imagination and perhaps form new paths in the readers mind. Some times I start the design of a new example and I have so much fun that the issues I wanted to explore become hidden and forgotten. A purely systematic presentation becomes boring and therefore not very pedagogic.

The manual for Povray was develop as a systematic presentation of various technical issues. It is a great reference guide and I use it very often. In contrast to that sequential and systematic approach we will follow more of an spiral approach, coming back to the same issues many times and each time in greater depth.

The scenes presented as examples in our series hope to provide not only an illustration to the technical issue at hand but also some aesthetic example of how that particular technique could be used to produce beautiful results. This goal may require on occasions to introduce new and foreign elements of POVRAY not yet discussed in the series. Please do not worry if you do not understand everything yet, step by step we will cover every issue in the examples. On the other hand many techniques used are so visual in nature that they hardly require a written explanation because just "seeing" the result of the example is worth more than a lengthy explanation. Those who really wish to advance faster learning Povray can always go to the reference manual.

Simple Geometrical Objects

Most of these objects have been already used in previous examples. Let us review them now to bring all this information together.

The number of objects that can be designed based on the following series of simple geometrical objects is countless, thus reducing objects to an ensemble of elemental forms represents a considerable savings of time processing the scene. Here is our list:

Constraint Solid Graphics(CSG)

CGS primitives are elementary solid objects that can be combined into more complex models. The final combination can be grouped and transformed using scaling, translations, rotations transformations or filling in textures, etc... It is not necessary to to apply each of these transformations to each and everyone of the elementary primitives in the combined model.

There are four methods to combine CGS primitives, and there is a fifth complement method that applies to single primitives:

In the following examples we will use several of these operations to build solid models. I recommend to build models by adding first all the elements needed to make the overall volume and then using intersection operations to eliminate the undesired parts.

#define EatenApple = intersection { 
      object { WholeApple } 
      object { Bite1 inverse } 
      object { Bite2 inverse } 

When primitives objects in a solid model have common surfaces there may be problems of rendering points in one of the other surface due to machine precission. This problem can be worked around by introducing a very small translation in one the objects to clearly distinguish to which object the surface belongs to.

Loops and Conditionals in Povray.

The elements in a scene are described generally in an arbitrary order. Nevertheless there are occasions when it is very convenient to implement procedural loops to create iterative structures, for example. Loops can be implemented in Povray using several methods. One method is the loop flow control directive provided by the language itself.

The loop flow control is just one of many directives of the POVRAY programming interface. Some while ago we mentioned other directives like #declare and #include and we characterized many others as of minor importance. The example that follows was edited directly in POVRAY and I must confess this is the first time I use the loop flow control directive. The reason is that often it is possible to achieve the same result by generating the POVRAY source with a separate program (C or C++) that has loop flow control statements (for loop). We will see at some point an example of this technique.

The reader with C experience will understand that Povray's programming interface is not as elegant as other general purpose programming languages (C, C++). This should not come as a surprise because POVRAY was designed as a language for the description of scenes, and the flow control directives were later additions. Similarly, POVRAY includes directives for performing complex mathematical operations and all kind of loops. Personally I believe it is fantastic that POVRAY includes all these operations, on the other hand they are not really not absolutely necessary since we can alway execute them externally in more powerful programming languages. I do not see how performing these operations externally or internally makes any difference to the final artistic value of the composition. For me the most important issue is the quality of the final image. To a lesser extent it should also be a factor the time and effort required to develop and process the image. Users more familiar with general purpose languages may feel better generating POVRAY files through them, others without programming experience perhaps would feel more comfortable writing directly in POVRAY. Also for simple images direct editing in POVRAY is easier while for complex scenes the generation of POVRAY files by other programs may be better. We will explore both methods and let the reader pick accordingly.

Using the Trial and Error Method

Many scenes can be designed starting from a simple idea. After a first implementation we may decide to change some value or use approximations to achieve a better result. So trial and error is an integral part of scene design in POVRAY. At the beginning of this series of articles we offered readers a simple script-tool (POV) to facilitate the generation of images, but the reader should not think that this little script is sufficient. Often times you will need plain paper, pencil and a calculator. In many occasions there is no choice because our designs involved 3D geometries, some knowledge of special geometry and trigonometry are fundamental in order to achieve certain effects. Generally it is sufficient to know a few formulas, so let us remember some basic trigonometric relationships:

sin(a) = A / C = (Opposite side / Hypotenuse)
cos(a) = B / C = (Adjacent side / Hypotenuse)
tan(a) = A / B = (Opposite size / Adjacent side)


A = sin(a)/C
B = cos(a)/C
C = sqrt(A^2 + B^2)
Since 2* Pi radians = 360º

1 Radian = 180 / Pi = 57,29577951308232
1º = Pi / 180 = 0,174532925199432957

Next as a reminder we will tabulate the main domains for the trigonometric functions as a function of the quadrant:

Quadrant Sine Cosine Tangent
0 .. 90 0 .. +1 +1 .. 0 0 .. +Infinity
90 .. 180 +1 .. 0 0 .. -1 -Infinity .. 0
180 .. 270 0 .. -1 -1 .. 0 0 .. +Infinity
270 .. 360 -1 .. 0 0 .. +1 -Infinity .. 0

a = atan(A/B)

This last relationship is not uniquely defined. The angle alpha is undetermined by +/- 180 degrees.Computationally it is preferably to use this:

a = atan2(A,B)

Finally the distance from P1(x1,y1,z1) to P2(x2,y2,z2) is

D = sqrt( (x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2 )

There are many usefull trigonometric relationships but the ones already reviewed should be sufficient for most cases. The implicit trigonometric functions implemented in POVRAY assume by default angles in radians. The conversion function radians(alpha) transforms degrees to radians. Unfortunately POVRAY is not consistent, for example rotations are measured in degrees! :-(


In the following example we use some very basic trigonometry. The spikes in the sea-urchin are placed very conveniently, and this effect cannot be easily achieved by chance. The designer has to think about an algorithm to place the spikes exactly and implement it with a clear idea of the final 3D configuration. The source code for the example is sufficiently documented, so it is not worth to make further comments here. This example is a clear case where a loop algorithm applies. Whether the designer decides to implement the loop within POVRAY or outside via a C-program is a matter of personal choice.


Here are the sources for the fish. They are modeled using CGS primitives as previously described.


Next comes the sources for the remaining scene. The most peculiar issue here is the definition of the sea-urchin (erizo in Spanish) that without a doubt are the principal characters in the composition:


A number of effects in this example are completely new, for example the surface effects on the sand (waves on the sand), the atmospheric effects (a fog of green marine color very thick and very humid) and the complex CGS objects as well. The light in the scene comes from many point sources disperse over the medium to simulate the underwater illumination, characterized by the disorder scattering from the waves on the surface. A single light source would be inappropriate for this composition because it would the shadow of the sea-urchin would be too sharp.

Generation by External Programs.

A ray-tracer is merely a tool to generate a complete scene specified with the help of a formal ray-tracing language. Ray-traces are able to understand color and light specifications, etc... Often times there is previous work to support our design work: 3D scanners, format conversion tools, programs, among others. Therefore a ray-tracer is just one in a chain of of tools for scene construction and design. In other words, design by typing on the keyboard our ideas is not the only mechanism for producing artistic compositions, we have auxiliary tools to produce more complex compositions that are not so easily type by hand in a ray-tracer language.

As an example of a complex scene generated by an external program we will next provide a C-program names burbujas.c (bubbles). The program places a number of bubbles at random on a surface of size 1000x750 pixels. Bubbles cannot intersect amongst themselves, so our example code determines random positions and random sizes accordingly. If the new location generated by for a bubble falls near an existing bubble a new position is then computed. The size of the sphere is reduced to make them fit. After a large number of iterations one obtains a surface with almost no free space left. The generation of this particular example requires a lot of computation because as the sequence progresses in becomes harder and harder to fit a new bubble.


Compile and run this program. Redirect the standard output to a file name 'burbujas.inc' where the data for the bubbles remain stored (burbujas > burbujas.inc). The output file contains entries as these:

sphere{<-375, 0,   33> 55.0000000 texture{Gold_Metal}} //(0/1) 
sphere{< -86, 0,   62> 55.0000000 texture{Gold_Metal}} //(1/2) 
sphere{<-326, 0,  346> 55.0000000 texture{Gold_Metal}} //(2/3) 
sphere{< 190, 0, -156> 55.0000000 texture{Gold_Metal}} //(3/4) 
sphere{<  62, 0, -293> 55.0000000 texture{Gold_Metal}} //(4/5) 
sphere{< 323, 0,  161> 55.0000000 texture{Gold_Metal}} //(5/6) 
sphere{< 341, 0,  -15> 55.0000000 texture{Gold_Metal}} //(6/7) 

I recommend some patience because it takes a while to generate the output file. At any moment you can interrupt the process and edit the output file to make sure that the last entry line is complete. If not just remove it from the file. The source for pov will the following:


The source code contains again references to the token "clock" but this time its purpose is very different. In this case it does not generate a sequence of images for an animation but four images with very different points of view. The position, angle and aperture of the camera varies among the four images.

In the previous POVRAY article we already mentioned that at some point we would examine examples that explore the possibilities of the camera in POVRAY. Well this is one example. It is quite obvious the differences on the final rendered image according to the specifications of the camera. One can achieve many perspectives according to the angle of aperture: small angle yields far perspectives while wide angles yield close-ups. The maximum angle is 180 degrees, it is a very extreme value because it is hard to distinguish shapes.

The images shown were processed on a Pentium 200 MMX 48MB Ram (398 bogomips). It was executed as suggested by using the tool provided earlier in the series, 'pov':

pov burbujas 6 9 1 5 1 5
Total Time =

The parameter passed represent:

The time spend to generate each photogram is considerable. With better quality it would take the following times:

pov burbujas 9 9 1 5 1 5

Total time = 4 1/2 hours .
First photogram 2 minutes
Second photogram 5 minutes.
Third photogram 10 minutes
Fourth photogram 13 minutes
Fifth photogram 4 hours !!

Let us examine now the results. In the first of the four photograms the only variation is the camera setup. (position, angle, orientation, etc)

Before showing the last photogram let me go over another issue that is relevant to appreciate this last image, the issue of CPU optimization.

CPU Usage Optimization

The last photogram is the most complex and POVRAY was not able to optimize it. When confronted by complex compositions the ray-tracer tries to simplify the scene to the simplest common denominator. In previous versions of POVRAY the optimizations had to be done by hand; to this end artists had the directive 'bounded_by' to specify a primitive that would wrap one or more objects. Then the ray-tracer assumed that rays that did not collide with this wrapping would not collide either with any of the objects inside. This is an approximation that saves some processing time. There are very few cases where it is actually useful. As it turns out, our last image is one of those cases!. The last image contains to many objects and is very complex. Therefore it would have been better to manually optimize the composition, for example by grouping bubbles by zones, joining bubbles into compound objects, or even combining all the bubbles in one object but wrapping groups of spheres within the same region using the command 'bounde_by'. The syntax would be:

    union { 
    sphere { <x1, y1, z1>, r1 }  
    sphere { <x2, y2, z2>, r1 } 
    sphere { <x3, y3, z3>, r1 } 
    bounded_by { sphere { <xb, yb, zb>, rb } } 

The type of manual optimization described can be used with unions and intersections and also with any other object. The user may also select other wrapping primitives, we chose a sphere, however the best results are often obtained with boxes and spheres. If the primitive selected leaves part of the compound object outside the result can be defective.

Once again I would like to stress that the need for manual optimizations is rare. Our last example was conceived with 'bad intentions' beforehand in order to raise the issue. POVRAY automatic optimizer was unable to handle any better the composition. It contains 2154 spheres. The reader could check it out counting them :-).

In our example we have shown how to play with the possibilities of the ray-tracer. Many times the same idea or concept can be implemented in various ways to obtain diverse results and here is where the artist's creativity surfaces.

What is missing...

Povray provides many mathematical functions, some more or less interesting. Unfortunately there is one very interesting function missing. It is the "spline". There is nothing as convenient as tracing with pencil and paper a few points and then applying a function that draws a smooth line across the points. Povray's spline primitive can not be used as a function, instead it generates a line as the basis for building other forms, it would be better if we could apply the spline to any variables we wish. That would allow for example to make the camera follow an arbitrary trajectory. I would also be great if one could implement external functions. To some degree all these can be achieve by using includes and external programming. Under Linux we have a utility named 'spline'. It can be used as a command to generate the desired curve from a set of points. Try to combine this command with external programming, for example to generate animations or camera movement.


Reader contributions

I am eager to here from readers and see their compositions, perhaps employing the recursive or loop structures discussed here. Please send me you experiments in compress files. It would be great to collect readers collaborations and organize an exhibition here in the LinuxFocus magazine. I will select the most interesting or imaginative images for the exhibition. Please do not submit images under some kind of commercial for-pay license. If possible send also the sources for the images so that other people can learn from your ideas.