9.7.6  What about nested loops?

Even when one masters simple loops, nested loops can be a frightening thing (or at least hard to understand).

Nested loops are used for example for creating a 2D array of objects (with rows and columns of objects), etc. For example if you want to create a 10x20 array of spheres in your scene, a nested loop is the tool for it.

There's nothing special about nested loops. You only have to pay attention to where you initialize and update your index variables.

Let's recall the form of a simple for-loop:

#declare Index = initial_value;
#while(Index <= final_value)

  [Something here]

  #declare Index = Index + index_step;
#end

The [Something here] part can be anything. If it's another while-loop, then we have nested loops. The inner loop should have the same structure as the outer one.

Note that proper indentation helps us distinguishing between the loops. It's always a good idea to use a good indentation scheme:

#declare Index1 = initial_value1;
#while(Index1 <= final_value1)

   #declare Index2 = initial_value2;
   #while(Index2 <= final_value2)

      [Something here]

      #declare Index2 = Index2 + index2_step;
   #end

   #declare Index1 = Index1 + index1_step;
#end

It's a common mistake for beginners to break this structure. For example it's common to declare the 'Index2' before the first #while. This breaks the for-loop structure and thus doesn't work. If you follow step by step what POV-Ray does, as explained earlier, you will see why it doesn't work. Don't mix the structures of the inner and the outer loops together or your code will simply not work as expected.

So, if we want to make our 10x20 array of spheres, it will look like this:

#declare Index1 = 0;
#while(Index1 <= 9)

   #declare Index2 = 0;
   #while(Index2 <= 19)

      sphere { <Index1, Index2, 0>, .5 }

      #declare Index2 = Index2 + 1;
   #end

   #declare Index1 = Index1 + 1;
#end

Note how we now start from 0 and continue to 9 in the outer loop and from 0 to 19 in the inner loop. This has been done to get the sphere array start from the origin (instead of starting from <1, 1, 0>). Of course we could have made the 'Index1' and 'Index2' go from 1 to 10 and from 1 to 20 respectively and then created the sphere in this way:

  sphere { <Index1-1, Index2-1, 0>, .5 }

Although you should not mix the loop structures together, you can perfectly use the values of the outer loop in the inner loop (eg. in its condition). For example, if we wanted to create a triangular array of spheres instead of a rectangular one (that is, we create only half of the spheres), we could have made the inner #while like this:

  #while(Index2 < Index1*2)

('Index2' will go from 0 to the value of 'Index1' multiplied by 2.)

There's no reason why we should limit ourselves to just two nested loops. There's virtually no limit how many loops you can nest. For example, if we wanted to create a box-shape filled by spheres rows, colums and depth, we just make three nested loops, one for the x-axis, another for the y-axis and the third for the z-axis.