Difference between revisions of "Documentation:Tutorial Section 3.8"

From POV-Wiki
Jump to navigation Jump to search
m (removed famous quote in 1 place)
m (Indexentries fix)
 
(9 intermediate revisions by 2 users not shown)
Line 7: Line 7:
 
<br>
 
<br>
 
<!--</wikitalk>--->
 
<!--</wikitalk>--->
===Do Not Use Jitter Or Crand===
+
<!--REMOVE--->===Making Animations===<!--THIS--->
<!--<indexentry "Animation, not using jitter or crand with">--->
+
====Do Not Use Jitter Or Crand====
<!--<indexentry "jitter, in animations">--->
+
{{#indexentry:Animation, not using jitter or crand with}}
<!--<indexentry "crand, in animations">--->
+
{{#indexentry:jitter, in animations}}
 +
{{#indexentry:crand, in animations}}
 
<p> One last piece of basic information to save frustration. Because jitter
 
<p> One last piece of basic information to save frustration. Because jitter
 
is an element of anti-aliasing, we could just as easily have mentioned this
 
is an element of anti-aliasing, we could just as easily have mentioned this
Line 17: Line 18:
 
POV-Ray, so now is as good a time as any.</p>
 
POV-Ray, so now is as good a time as any.</p>
 
<p>
 
<p>
<!--<linkto "Jitter">Jitter</linkto>--->[[Documentation:Reference Section 4.4#Area Lights|Jitter]] is a very small amount of random ray perturbation designed to diffuse
+
[[Reference:Light Source#Area Lights|Jitter]] is a very small amount of random ray perturbation designed to diffuse
 
tiny aliasing errors that might not otherwise totally disappear, even with
 
tiny aliasing errors that might not otherwise totally disappear, even with
 
intense anti-aliasing. By randomizing the placement of erroneous pixels, the
 
intense anti-aliasing. By randomizing the placement of erroneous pixels, the
Line 36: Line 37:
 
(relatively) small extra measure quality due to the use of jitter will be
 
(relatively) small extra measure quality due to the use of jitter will be
 
offset by the ocean of jumpies that results. This general rule also applies
 
offset by the ocean of jumpies that results. This general rule also applies
to any truly random texture elements, such as <code><!--<linkto "crand">crand</linkto>--->[[Documentation:Reference Section 5.1#Crand Graininess|crand]]</code>.</p>
+
to any truly random texture elements, such as <code>[[Reference:Finish#Crand Graininess|crand]]</code>.</p>
  
===INI File Settings===
+
====INI File Settings====
<!--<indexentry "Animation, INI file settings for">--->
+
{{#indexentry:Animation, INI file settings for}}
<!--<indexentry "initial_frame, ini-option, tutorial">--->
+
{{#indexentry:initial_frame, ini-option, tutorial}}
<!--<indexentry "final_frame, ini-option, tutorial">--->
+
{{#indexentry:final_frame, ini-option, tutorial}}
<!--<indexentry "initial_clock, ini-option, tutorial">--->
+
{{#indexentry:initial_clock, ini-option, tutorial}}
<!--<indexentry "final_clock, ini-option, tutorial">--->
+
{{#indexentry:final_clock, ini-option, tutorial}}
 
<p>Okay, so we have a grasp of how to code our file for animation. We know
 
<p>Okay, so we have a grasp of how to code our file for animation. We know
 
about the clock variable, user declared clock-relative variables, and the
 
about the clock variable, user declared clock-relative variables, and the
Line 50: Line 51:
 
<p>
 
<p>
 
The first concept we will need to know is the INI file settings,
 
The first concept we will need to know is the INI file settings,
<code><!--<linkto "Initial_Frame, ini-option">Initial_Frame</linkto>--->[[Documentation:Reference Section 1#Internal Animation Loop|Initial_Frame]]</code> and
+
<code>[[Reference:Animation Options#Internal Animation Loop|Initial_Frame]]</code> and
<code><!--<linkto "Final_Frame, ini-option">Final_Frame</linkto>--->[[Documentation:Reference Section 1#Internal Animation Loop|Final_Frame]]</code>. These are very handy
+
<code>[[Reference:Animation Options#Internal Animation Loop|Final_Frame]]</code>. These are very handy
 
settings that will allow us to render a particular number of frames and each
 
settings that will allow us to render a particular number of frames and each
 
with its own unique frame number, in a completely hands free way. It is of
 
with its own unique frame number, in a completely hands free way. It is of
Line 78: Line 79:
 
example, from 0.0 to 2.0, we would just add to your INI file the lines</p>
 
example, from 0.0 to 2.0, we would just add to your INI file the lines</p>
 
<code>
 
<code>
<!--<linkto "Initial_Clock, ini-option">Initial_Clock</linkto>--->[[Documentation:Reference Section 1#Internal Animation Loop|Initial_Clock]] = 0.0<br>
+
[[Reference:Animation Options#Internal Animation Loop|Initial_Clock]] = 0.0<br>
<!--<linkto "Final_Clock, ini-option">Final_Clock</linkto>--->[[Documentation:Reference Section 1#Internal Animation Loop|Final_Clock]] = 2.0<br>
+
[[Reference:Animation Options#Internal Animation Loop|Final_Clock]] = 2.0<br>
 
</code>
 
</code>
  
Line 99: Line 100:
 
need two new INI settings</p>
 
need two new INI settings</p>
 
<code>
 
<code>
<!--<linkto "Subset_Start_Frame">Subset_Start_Frame</linkto>--->[[Documentation:Reference Section 1#Subsets of Animation Frames|Subset_Start_Frame]] = 51<br>
+
[[Reference:Animation Options#Subsets of Animation Frames|Subset_Start_Frame]] = 51<br>
<!--<linkto "Subset_End_Frame">Subset_End_Frame</linkto>--->[[Documentation:Reference Section 1#Subsets of Animation Frames|Subset_End_Frame]] = 75<br>
+
[[Reference:Animation Options#Subsets of Animation Frames|Subset_End_Frame]] = 75<br>
 
</code>
 
</code>
  
Line 128: Line 129:
  
 
===While-loop tutorial===
 
===While-loop tutorial===
<p>Usually people who have never
+
<p>Usually people who have never programmed have great difficulties understanding how simple while-loops work and how they should be used. When you get into nested loops, the problem is even worse.</p>
programmed have great difficulties understanding how simple while-loops
+
<p>Sometimes even people who have programmed a bit with some language get confused with POV-Ray's while-loops. This usually happens when they have only used a for-loop which in itself has an index variable which is often incremented automatically.</p>
work and how they should be used. When you get into nested loops, the problem is even worse.
 
 
 
</p>
 
<p>Sometimes even people who have programmed a bit with some language get
 
confused with POV-Ray's while-loops. This usually happens when they have
 
only used a for-loop which in itself has an index variable (which is often
 
even incremented automatically).
 
</p>
 
 
 
===What a while-loop is and what it is not===
 
<p>A while-loop in POV-Ray is just a control structure which tells POV-Ray
 
to loop a command block while the specified condition is true (ie.
 
until it gets false).
 
 
 
</p>
 
<p>That is, a while-loop is like this:</p>
 
  
 +
====What a while-loop is and what it is not====
 +
<p>A while-loop in POV-Ray is just a control structure which tells POV-Ray to repeat a command block while the specified condition is true.</p>
 +
<p>The while-loop syntax is as follows:</p>
 
<pre>
 
<pre>
 
#while(condition)
 
#while(condition)
Line 152: Line 140:
 
#end
 
#end
 
</pre>
 
</pre>
 +
<p>The commands between <code>#while</code> and <code>#end</code> are run over and over as long as the condition evaluates to true.</p>
 +
<p>A while-loop <strong>is not</strong> a for-loop nor any kind of loop which has an index variable that may be incremented automatically with each iteration.</p>
 +
<p>The while loop <strong>does not</strong> care what the conditions are between the parentheses as long as they evaluate to some value, nor what the block between <code>#while</code> and <code>#end</code> contains. It will just execute that block until the condition becomes false.</p>
 +
<p>The while-loop does not do anything else. You can think of it as a &quot;simple&quot; loop, which does not do anything automatically. This is not necessarily a bad thing.</p>
  
<p>The commands between <code>#while</code> and <code>#end</code> are run over and over as long as
+
====How does a single while-loop work?====
the condition evaluates to true.
+
<p>The while loop works like this:</p>
 
 
</p>
 
<p>A while-loop <b>is not</b> a for-loop nor any kind of loop which has an
 
index variable by itself (which may be incremented automatically in each
 
loop).
 
 
 
</p>
 
<p>The while-loop <b>does not</b> care what the conditions are
 
between the parentheses (as long as they evaluate to some value) or
 
what does the block between <code>#while</code> and <code>#end</code> contain. It will just execute
 
that block until the condition becomes false.
 
 
 
</p>
 
<p>The while-loop does not do anything else. You can think about it as a kind
 
of &quot;dumb&quot; loop, which does not do anything automatically (and this is not
 
necessarily a bad thing).</p>
 
 
 
===How does a single while-loop work?===
 
<p>The while-loop works like this:
 
 
 
 
<ol>
 
<ol>
<li>If the condition between the parentheses evaluates to false, jump to
+
<li>If the condition between the parentheses evaluates to false, jump to the command after the <code>#end</code> statement. If the condition evaluates to true, just continue normally.</li>
the command after the <code>#end</code> statement. If the condition evaluates to
 
true, just continue normally.</li>
 
 
<li>At the <code>#end</code> statement jump to the <code>#while</code> statement and start again.</li>
 
<li>At the <code>#end</code> statement jump to the <code>#while</code> statement and start again.</li>
 
</ol>
 
</ol>
 
+
<p>That is:</p>
</p>
 
<p>That is:
 
 
 
 
<ul>
 
<ul>
<li>When POV-Ray gets to the <code>#while</code> statement it evaluates the condition
+
<li>When POV-Ray gets to the <code>#while</code> statement it evaluates the condition between parentheses.</li>
between parentheses.</li>
+
<li>If the statement evaluated as true then it will just continue normally with the next command.</li>
<li>If the statement evaluated to true then it will just continue normally
+
<li>If the statement evaluated as false, POV-Ray will skip the entire body of the loop and continue with the command after the <code>#end</code> statement.</li>
with the next command.</li>
+
<li>At an <code>#end</code> statement POV-Ray will just jump back to the corresponding <code>#while</code> statement, and will conditionally execute the commands, if the condition evaluates true.</li>
<li>However, if the statement evaluated to false, POV-Ray will skip the
 
entire body of the loop and continue from the command after the <code>#end</code>
 
statement.</li>
 
<li>At an <code>#end</code> statement POV-Ray will just jump back to the corresponding
 
<code>#while</code>-statement and then continue normally (ie. testing the condition
 
and so on).</li>
 
 
</ul>
 
</ul>
 +
<p>Note that nowhere there is any mention about any index variable or anything else that could be used to automatically end the loop. As said, it is just a &quot;simple&quot; loop that continues forever if necessary, only testing the statement between the parentheses, and it is not interested in what it is, only in its evaluated value.</p>
 +
<p>Although one could easily think that this kind of simple loop is bad, and it should be more intelligent, the fact is that this kind of simple loop is actually a lot more flexible and versatile. It allows you to make things not possible or very difficult to do with an intelligent for-loop with automatic index variables.</p>
  
</p>
+
====How do I make a while-loop?====
<p>Note that nowhere there is any mention about any index variable or anything
+
<p>It depends on what you are trying to accomplish.</p>
else that could be used to automatically end the loop or whatever. As said,
+
<p>The most common usage is to use it as a simple for-loop, that is, a loop which loops a certain number of times, with an index value getting successive values (for example 1, 2, 3, ..., 10).</p>
it is just a &quot;dumb&quot; loop that continues forever if necessary, only testing
+
<p>For this you need to first declare your index identifier with the first value.</p>
the statement between the parentheses (but it is not interested in what it is,
 
only in its evaluated value).
 
 
 
</p>
 
<p>Although one could easily think that this kind of &quot;dumb&quot; loop is bad and
 
it should be more &quot;intelligent&quot; and better, the fact is that this kind of
 
&quot;dumb&quot; loop is actually a lot more flexible and versatile. It allows you to
 
make things not possible or very difficult to do with an &quot;intelligent&quot;
 
for-loop with automatic index variables.</p>
 
 
 
===How do I make a while-loop?===
 
<p>It depends on what you are trying to make.
 
 
 
</p>
 
<p>The most common usage is to use it as a simple for-loop, that is, a loop
 
which loops a certain number of times (for example 10 times) with an index
 
value getting successive values (for example 1, 2, 3, ..., 10).
 
 
 
</p>
 
<p>For this you need to first declare your index identifier with the first
 
value. For example:
 
 
 
 
<pre>
 
<pre>
 
#declare Index = 1;
 
#declare Index = 1;
 
</pre>
 
</pre>
 
+
<p>If you want to loop 10 times, remember how the condition worked: The while-loop repeats as long as the condition is true. So it should loop as long as our 'Index' identifier is less or equal to 10</p>
</p>
 
<p>Now you want to loop 10 times. Remember how the condition worked: The
 
while-loop loops as long as the condition is true. So it should loop as long
 
as our 'Index' identifier is less or equal to 10:
 
 
 
 
<pre>
 
<pre>
 
#while(Index &lt;= 10)
 
#while(Index &lt;= 10)
 
</pre>
 
</pre>
 
+
<p>When the value of 'Index' is 11 the loop ends, as it should.</p>
</p>
+
<p>We only have to add 1 to 'Index' at the end of each loop</p>
<p>When the 'Index' gets the value 11 the loop ends, as it should.
 
 
 
</p>
 
<p>Now we only have to add 1 to 'Index' at each loop, so we should do it
 
at the end of the loop, thus getting:
 
 
 
 
<pre>
 
<pre>
 
#declare Index = 1;
 
#declare Index = 1;
Line 253: Line 183:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>The incrementation before the <code>#end</code> is important. If we do not do it, 'Index' would always have the value 1 and the loop would go forever since 1 is always less or equal to 10.</p>
</p>
+
<p>What happens here?</p>
<p>The incrementation before the <code>#end</code> is important. If we do not do it, 'Index'
 
would always have the value 1 and the loop would go forever since 1 is always
 
less or equal to 10.
 
 
 
</p>
 
<p>What happens here?
 
 
 
 
<ol>
 
<ol>
 
<li>First POV-Ray sets the value 1 to 'Index'.</li>
 
<li>First POV-Ray sets the value 1 to 'Index'.</li>
<li>Then it sees the <code>#while</code> statement and evaluates what is between the
+
<li>Then it sees the <code>#while</code> statement and evaluates what is between the parentheses: Index &lt;= 10</li>
parentheses: Index &lt;= 10</li>
+
<li>As 'Index' has the value of 1 and 1 &lt;= 10, the condition evaluates to true.</li>
<li>As 'Index' has the value of 1 and 1 &lt;= 10, the condition evaluates to
+
<li>So, it just continues normally, and executes the commands following the <code>#while</code> statement, as noted in the above example as (some commands here).</li>
true.</li>
+
<li>Then it arrives normally to the last #declare command in the block. This causes the value 2 to be assigned to 'Index'.</li>
<li>So, it just continues normally. It executes the commands following
 
the <code>#while</code> statement (denoted in the above example as
 
&quot;(some commands here)&quot;).</li>
 
<li>Then it arrives normally to the last #declare command in the block.
 
This causes the value 2 to be assigned to 'Index'.</li>
 
 
<li>Now it arrives the the <code>#end</code> command and so it just jumps to the <code>#while</code>.</li>
 
<li>Now it arrives the the <code>#end</code> command and so it just jumps to the <code>#while</code>.</li>
<li>After that it executes the steps 2-6 again because also 2 is less or
+
<li>After that it executes the steps 2-6 again because 2 is also less or equal to 10.</li>
equal to 10.</li>
+
<li>After this has been done 10 times, the value 11 is assigned to 'Index' in the last command of the block.</li>
<li>After this has been done 10 times, the value 11 is assigned to 'Index'
+
<li>Now, when POV-Ray evaluates the condition it sees that it is false, because 11 is not less or equal to 10. This causes POV-Ray to jump to the command after the <code>#end</code> statement.</li>
in the last command of the block.</li>
+
<li>The net effect of all this is that POV-Ray looped 10 times and the 'Index' variable was assigned successive values from 1 to 10 along the way.</li>
<li>Now, when POV-Ray evaluates the condition it sees that it is false
 
(because 11 is not less or equal to 10). This causes POV-Ray to jump
 
to the command after the <code>#end</code> statement.</li>
 
<li>The net effect of all this is that POV-Ray looped 10 times and the
 
'Index' variable got successive values from 1 to 10 along the way.</li>
 
 
</ol>
 
</ol>
 +
<p>If you read carefully the above description you will notice that the looping is done in a quite simple way, that is, there is no higher logic hidden inside the loop structure. In fact, POV-Ray does not have the slightest idea how many times the loop is executed and what variable is used to count the loops. It just follows orders.</p>
 +
<p>The higher logic in this type of loop is in the combination of commands we wrote. The effect of this combination is that the loop works like a simple for-loop in most programming languages (like BASIC, etc).</p>
  
</p>
+
====What is a condition and how do I make one?====
<p>If you read carefully the above description you will notice that the
+
<p>A condition is an expression that evaluates to a boolean value (ie. true or false) and is used in POV-Ray in <code>#while</code> loops and <code>#if</code> statements.</p>
looping is done in a quite &quot;dumb&quot; way, that is, there is no higher logic
+
<p>A condition is mainly a comparison between two values, although there are also some other ways of making a condition, that is not important now.</p>
hidden inside the loop structure. In fact, POV-Ray does not have the slightest
+
<p>For example:</p>
idea how many times the loop is executed and what variable is used to
 
count the loops. It just follows orders.
 
 
 
</p>
 
<p>The higher logic in this type of loop is in the combination of commands
 
we wrote. The effect of this combination is that the loop works like a
 
simple for-loop in most programming languages (like BASIC, etc).</p>
 
 
 
===What is a condition and how do I make one?===
 
<p>A condition is an expression that evaluates to a boolean value (ie. true
 
or false) and is used in POV-Ray in <code>#while</code>-loops and <code>#if</code>-statements.
 
 
 
</p>
 
<p>A condition is mainly a comparison between two values (although there
 
are also some other ways of making a condition, but that is not important
 
now). For example:
 
 
 
 
<pre>
 
<pre>
 
1 &lt; 2  is true
 
1 &lt; 2  is true
Line 311: Line 209:
 
1 = 1  is true
 
1 = 1  is true
 
1 = 2  is false
 
1 = 2  is false
 
and so on.
 
 
</pre>
 
</pre>
 
+
<p>Usually it makes no sense to make comparisons like those. However, when comparing identifiers with some value or two identifiers together it starts to be very useful. Consider this:</p>
</p>
 
<p>Usually it makes no sense to make comparisons like those. However, when
 
comparing identifiers with some value or two identifiers together it
 
starts to be very useful. Consider this:
 
 
 
 
<pre>
 
<pre>
 
#if(version &lt; 3.1)
 
#if(version &lt; 3.1)
Line 325: Line 216:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>If the identifier called 'version' has a value which is less than 3.1 the <code>#error</code> line will be executed. If 'version' has a value which is 3.1 or greater, the <code>#error</code> line is just skipped.</p>
</p>
+
<p>You can combine conditions together with the boolean operators &amp; (and) and | (or). You can also invert the value of a condition with ! (not).</p>
<p>If the identifier called 'version' has a value which is less than 3.1 the
+
<p>For example, if you want something to be done when 'a' is less than 10 <strong>and</strong> 'b' is greater or equal to 20, the condition would be:</p>
<code>#error</code> line will be executed. If 'version' has a value which is 3.1 or
 
greater, the <code>#error</code> line is just skipped.
 
 
 
</p>
 
<p>You can combine conditions together with the boolean operators &amp; (and)
 
and | (or). You can also invert the value of a condition with ! (not).
 
 
 
</p>
 
<p>For example, if you want something to be done when 'a' is less than 10
 
<b>and</b> 'b' is greater or equal to 20, the condition would be:
 
 
 
 
<pre>
 
<pre>
 
a&lt;10 &amp; b&gt;=20
 
a&lt;10 &amp; b&gt;=20
 
</pre>
 
</pre>
 +
<p>For more information about these comparison operators, see the [[Reference:Numeric Expressions#Operators|Operators]] section of the POV-Ray documentation.</p>
  
</p>
+
====What about loop types other than simple for-loops?====
<p>For more information about these comparison operators, see the
+
<p>As POV-Ray does not care what the condition is and what we are using to make that condition, we can use the while-loop in many other ways.</p>
<!--<linkto "Float, operators">'Float operators'</linkto>--->[[Documentation:Reference Section 2#Operators|'Float operators']]
+
<p>For example, this is a typical use of the while-loop that is not just a simple for-loop:</p>
section of the POV-Ray documentation.</p>
 
 
 
===What about loop types other than simple for-loops?===
 
<p>As POV-Ray does not care what the condition is and what we are using to
 
make that condition, we can use the while-loop in many other ways.
 
 
 
</p>
 
<p>For example, this is a typical use of the while-loop which is not a
 
simple for-loop:
 
 
 
 
<pre>
 
<pre>
 
#declare S = seed(0);
 
#declare S = seed(0);
Line 363: Line 234:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>We take a random point between &lt;-1, -1, -1&gt; and &lt;1, 1, 1&gt; and if it is not inside the unit sphere take another random point in that range until we get a point inside the unit sphere.</p>
</p>
+
<p>This is not an unrealistic example since it is very handy, and we can plainly see, this looks nothing like an ordinary for-loop.</p>
<p>What we are doing here is this: Take a random point between
 
&lt;-1, -1, -1&gt; and &lt;1, 1, 1&gt; and if it is not inside the unit sphere
 
take another random point in that range. Do this until we get a point inside
 
the unit sphere.
 
 
 
</p>
 
<p>This is not an unrealistic example since it is very handy.
 
 
 
</p>
 
<p>As we see, this has nothing to do with an ordinary for-loop:
 
 
 
 
<ul>
 
<ul>
<li>It does not have any &quot;index&quot; value which gets consecutive values during
+
<li>It does not have any 'index' value which gets consecutive values during the loop.</li>
the loop.</li>
+
<li>We do not know how many times it will loop. In this case it loops a random number of times.</li>
<li>We do not know how many times it will loop. In this
+
<li>Usually for-loops are used to place or create a series of objects. For each iteration another instance of that object is created. Here, however, we are only interested in the value that results <strong>after</strong> the loop, not the values inside it.</li>
case it loops a random number of times.</li>
 
<li>For-loops are usually used to get a series of things (eg. objects). At
 
each loop another instance of that thing is created. Here, however,
 
we are only interested in the value that results <b>after</b> the loop,
 
not the values inside it.</li>
 
 
</ul>
 
</ul>
 
+
<p>As we can see, a while-loop can also be used for a variety of tasks, for instance, to calculate a value or some values until the result is inside a specified range.</p>
</p>
+
<p>By the way, there is a variant of this kind of loop where the task would be to calculate a value until the result is inside a specified range, but make only a certain number of tries. If the value does not get inside that range after that number of tries, stop trying. This is used when there is a possibility for the loop for going on forever.</p>
<p>As we can see, a while-loop can also be used for a task of type
+
<p>In the above example about the point inside the unit sphere we do not need this because the random point will surely hit the inside of the sphere at some time. In some other situations, however, we cannot be so sure.</p>
&quot;calculate a value or some values until the result is inside a specified
+
<p>In this case we need a regular index variable to count the number of loops. If we reach a predetermined number of iterations, then we stop.</p>
range&quot; (among many other tasks).
+
<p>Suppose that we wanted to modify our point searching program to be completely safe and to try only up to 10 times. If the point does not hit the inside of the sphere after 10 tries, we just give up and use the point &lt;0,0,0&gt;.</p>
 
 
 
 
</p>
 
<p>By the way, there is a variant of this kind of loop where the task is:
 
&quot;Calculate a value until the result is inside a specified range, but make
 
only a certain number of tries. If the value does not get inside that range
 
after that number of tries, stop trying&quot;. This is used when there is a
 
possibility for the loop for going on forever.
 
 
 
</p>
 
<p>In the above example about the point inside the unit sphere we do not need
 
this because the random point will surely hit the inside of the sphere at some
 
time. In some other situations, however, we cannot be so sure.
 
 
 
</p>
 
<p>In this case we need a regular index variable to count the number of
 
loops. If we have made that amount of loops then we stop.
 
 
 
</p>
 
<p>Suppose that we wanted to modify our point searching program to be
 
completely safe and to try only up to 10 times. If the point does not hit
 
the inside of the sphere after 10 tries, we just give up and take the
 
point &lt;0,0,0&gt;.
 
 
 
 
<pre>
 
<pre>
 
#declare S = seed(0);
 
#declare S = seed(0);
Line 428: Line 259:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>What did we do?</p>
</p>
 
<p>What did we do?
 
 
 
 
<ul>
 
<ul>
<li>We added an 'Index' value which counts the amount of loops gone so far.
+
<li>We added an 'Index' value which counts the amount of loops gone so far. It is quite similar to the index loop of a simple for-loop.</li>
It is quite similar to the index loop of a simple for-loop.</li>
+
<li>We added an extra condition to the while-loop: Besides testing that the point is outside the unit sphere it also tests that our index
<li>We added an extra condition to the while-loop: Besides testing that
+
variable has not bailed out. So now there are two conditions for the loop to continue: The 'Index' value must be less or equal to 10
the point is outside the unit sphere it also tests that our index
+
<strong>and</strong> the 'Point' has to be outside the unit sphere. If either one of them fails, the loop is ended.</li>
variable has not bailed out. So now there are two conditions for the
+
<li>Then we check if the point is still outside the unit sphere. If it is, we just take &lt;0,0,0&gt;.</li>
loop to continue: The 'Index' value must be less or equal to 10
 
<b>and</b> the 'Point' has to be outside the unit sphere. If either one
 
of them fails, the loop is ended.</li>
 
<li>Then we check if the point is still outside the unit sphere. If it is,
 
we just take &lt;0,0,0&gt;.</li>
 
 
</ul>
 
</ul>
 
+
<p>Sometimes it is not convenient to make the test again in the <code>#if</code> statement. There is another way of determining whether the loop bailed out without successful termination. Since the loop ends when the 'Index' gets the value 11, we can use this to test the successfulness of the loop</p>
</p>
 
<p>Btw, sometimes it is not convenient to make the test again in the <code>#if</code>
 
statement. There is another way of determining whether the loop bailed out
 
without successful termination or not: Since the loop ends when the 'Index'
 
gets the value 11, we can use this to test the successfulness of the loop:
 
 
 
 
<pre>
 
<pre>
 
#if(Index = 11)
 
#if(Index = 11)
Line 456: Line 273:
 
#end
 
#end
 
</pre>
 
</pre>
</p>
 
 
===What about nested loops?===
 
<p>Even when one masters simple loops, nested loops can be a frightening
 
thing (or at least hard to understand).
 
 
</p>
 
<p>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.
 
 
</p>
 
<p>There is nothing special about nested loops. You only have to pay
 
attention to where you initialize and update your index variables.
 
 
</p>
 
<p>Let's recall the form of a simple for-loop:
 
  
 +
====What about nested loops?====
 +
<p>Even when one masters simple loops, nested loops can be a frightening thing, or at least hard to understand.</p>
 +
<p>Nested loops are used for example in creating a 2D array of objects, that is rows and columns of objects. For example if you want to create a 10x20 array of spheres in your scene, a nested loop is up to the task.</p>
 +
<p>There is nothing special about nested loops. You only have to pay attention to where you initialize and update your index variables.</p>
 +
<p>Let's recall the form of a simple for-loop:</p>
 
<pre>
 
<pre>
 
#declare Index = initial_value;
 
#declare Index = initial_value;
Line 483: Line 288:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>The [Something here] part can be anything. If it is another while-loop, then we have nested loops. The inner loop should have the same structure as the outer one.</p>
</p>
+
<p>Note that proper indentation helps us distinguishing between the loops. It is always a good idea to use a good indentation scheme:</p>
<p>The [Something here] part can be anything. If it is another while-loop,
 
then we have nested loops. The inner loop should have the same structure
 
as the outer one.
 
 
 
</p>
 
<p>Note that proper indentation helps us distinguishing between the loops.
 
It is always a good idea to use a good indentation scheme:
 
 
 
 
<pre>
 
<pre>
 
#declare Index1 = initial_value1;
 
#declare Index1 = initial_value1;
Line 508: Line 305:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>It is a common mistake for beginners to break this structure. For example it is common to declare the 'Index2' before the first <code>#while</code>. This breaks the for-loop structure and thus does not work. If you follow step by step what POV-Ray does, as explained earlier, you will see why it does not work. Do not mix the structures of the inner and the outer loops together or your code will simply not work as expected.</p>
</p>
+
<p>So, if we want to make our 10x20 array of spheres, it will look like this:</p>
<p>It is a common mistake for beginners to break this structure. For example
 
it is common to declare the 'Index2' before the first <code>#while</code>. This breaks
 
the for-loop structure and thus does not work. If you follow step by step
 
what POV-Ray does, as explained earlier, you will see why it does not work.
 
Do not mix the structures of the inner and the outer loops together or your
 
code will simply not work as expected.
 
 
 
</p>
 
<p>So, if we want to make our 10x20 array of spheres, it will look like this:
 
 
 
 
<pre>
 
<pre>
 
#declare Index1 = 0;
 
#declare Index1 = 0;
Line 535: Line 322:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>Notice 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 &lt;1, 1, 0&gt;, 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:</p>
</p>
 
<p>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 &lt;1, 1, 0&gt;). 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:
 
 
 
 
<pre>
 
<pre>
 
   sphere { &lt;Index1-1, Index2-1, 0&gt;, .5 }
 
   sphere { &lt;Index1-1, Index2-1, 0&gt;, .5 }
 
</pre>
 
</pre>
 
+
<p>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 <code>#while</code> like this:</p>
</p>
 
<p>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 <code>#while</code> like this:
 
 
 
 
<pre>
 
<pre>
 
   #while(Index2 &lt; Index1*2)
 
   #while(Index2 &lt; Index1*2)
 
</pre>
 
</pre>
 +
<p>'Index2' will go from 0 to the value of 'Index1' multiplied by 2.</p>
 +
<p>There is no reason why we should limit ourselves to just two nested loops. There is virtually no limit how many loops you can nest. For example, if we wanted to create a box-shape filled by spheres rows, columns 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.</p>
  
</p>
+
====Mixed-type nested loops====
<p>('Index2' will go from 0 to the value of 'Index1' multiplied by 2.)
+
<p>It is perfectly possible to put a for-loop inside a non-for-loop or vice-versa. Again, you just have to be careful, with experience it gets easier.</p>
 
+
<p>For example, suppose that we want to create 50 spheres which are randomly placed inside the unit sphere.</p>
</p>
+
<p>So the distinction is clear: First we need a loop to create 50 spheres, a for-loop type suffices, and then we need another loop inside it to calculate the location of the sphere. It will look like this:</p>
<p>There is no reason why we should limit ourselves to just two nested loops.
 
There is 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.
 
</p>
 
 
 
===Mixed-type nested loops===
 
<p>It is perfectly possible to put a for-loop inside a non-for-loop or
 
vice-versa. Again, you just have to be careful (with experience it gets
 
easier).
 
 
 
</p>
 
<p>For example, suppose that we want to create 50 spheres which are randomly
 
placed inside the unit sphere.
 
 
 
</p>
 
<p>So the distinction is clear: First we need a loop to create 50 spheres
 
(a for-loop type suffices) and then we need another loop inside it to
 
calculate the location of the sphere. It will look like this:
 
 
 
 
<pre>
 
<pre>
 
#declare S = seed(0);
 
#declare S = seed(0);
Line 598: Line 352:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>There are some important things to note in this specific example:</p>
</p>
 
<p>There are some important things to note in this specific example:
 
 
 
 
<ul>
 
<ul>
<li>Although this is a nested loop, the sphere is not created in the inner
+
<li>Although this is a nested loop, the sphere is not created in the inner loop but in the outer one. The reason is clear: We want to create 50 spheres, so the sphere creation has to be inside the loop that counts to 50. The inner loop just calculates an appropriate location.</li>
loop but in the outer one. The reason is clear: We want to create 50
+
<li>The seed value 'S' is declared outside all the loops although it is used only in the inner loop. Can you guess why? Putting it inside the outer loop would have caused an undesired result: Which one?</li>
spheres, so the sphere creation has to be inside the loop that counts
 
to 50. The inner loop just calculates an appropriate location.</li>
 
<li>The seed value 'S' is declared outside all the loops although it is used
 
only in the inner loop. Can you guess why? (Putting it inside the outer
 
loop would have caused an undesired result: Which one?)</li>
 
 
</ul>
 
</ul>
</p>
 
 
===Other things to note===
 
<p>There is no reason why the index value in your simple for-loop should step
 
one unit at a time. Since the while-loop does not care how the index changes,
 
you can change it in whichever way you want. Eg:
 
  
 +
====Other things to note====
 +
<p>There is no reason why the index value in your simple for-loop should step one unit at a time. Since the while-loop does not care how the index changes, you can change it in whichever way you want. For example:</p>
 
<pre>
 
<pre>
#declare Index = Index - 1; Decrements the index (be careful with the
+
#declare Index = Index - 1;   // Decrements the index (be careful with the while loop condition)
                            while loop condition)
+
#declare Index = Index + 0.2; // Increases by steps of 0.2
 
+
#declare Index = Index * 2;   // Doubles the value of the index at each step.
#declare Index = Index + 0.2; Increases by steps of 0.2
 
 
 
#declare Index = Index * 2; Doubles the value of the index at each step.
 
 
 
etc.
 
 
</pre>
 
</pre>
 
+
<p class="Note"><strong>Note:</strong> Be careful <em>where</em> you put your while-loop.</p>
 
+
<p>The example below illustrates a very common mistake:</p>
 
 
</p>
 
<p>- Be careful <b>where</b> you put your while-loop.
 
 
 
</p>
 
<p>I have seen this kind of mistake more than once:
 
 
 
 
<pre>
 
<pre>
 
#declare Index = 1;
 
#declare Index = 1;
Line 647: Line 377:
 
#end
 
#end
 
</pre>
 
</pre>
 
+
<p>You will probably immediately see the problem.</p>
</p>
+
<p>This code creates 10 blobs with one component each. It does not seem to make much sense. Most probably the user wanted to make one blob with 10 components.</p>
<p>You will probably see immediately the problem.
+
<p>Why did this mistake happen? It may be that the user thought that the while-loop must be the outermost control structure and did not realize that while-loops can be anywhere. For example, inside objects to create subcomponents.</p>
 
+
<p>The correct code is, of course:</p>
</p>
 
<p>This code creates 10 blobs with one component each. It does not seem to
 
make much sense. Most probably the user wanted to make one blob with 10
 
components.
 
 
 
</p>
 
<p>Why did this mistake happen? It may be that the user (more or less
 
subconsciously) thought that the while-loop must be the outermost control
 
structure and does not realize that while-loops can be anywhere, also inside
 
objects (creating subcomponents or whatever).
 
 
 
</p>
 
<p>The correct code is, of course:
 
 
 
 
<pre>
 
<pre>
 
blob
 
blob
Line 678: Line 394:
 
}
 
}
 
</pre>
 
</pre>
 
+
<p>The essential difference here is that it is only the sphere code which is run 10 times instead of the whole blob code. The net result is the same as if we had written the sphere code 10 times with proper values of 'Index'.</p>
</p>
+
<p>Be also careful with the placement of the braces. If you put them in the wrong place you can end up accidentally repeating an opening or a closing brace 10 times. Again, a proper indentation usually helps a lot with this, as seen in the above example.</p>
<p>The essential difference here is that it is only the sphere code which is
+
<p class="Note"><strong>Tip:</strong> You can use while-loops in conjunction with arrays to automate the creation of long lists of elements with differing data.</p>
run 10 times instead of the whole blob code. The net result is the same as
+
<p>Imagine that you are making something like this:</p>
if we had written the sphere code 10 times with proper values of 'Index'.
 
 
 
</p>
 
<p>Be also careful with the placement of the braces. If you put them in
 
the wrong place you can end up accidentally repeating an opening or a closing
 
brace 10 times. Again, a proper indentation usually helps a lot with this
 
(as seen in the above example).
 
 
 
 
 
</p>
 
<p>- Tip: You can use while-loops in conjunction with arrays to automatize
 
the creation of long lists of elements with differing data.
 
 
 
</p>
 
<p>Imagine that you are making something like this:
 
 
 
 
<pre>
 
<pre>
  color_map
+
color_map {
   [0.00 rgb &lt;.1,1,.6&gt;]
+
   [0.00 rgb &lt;.1,1,.6&gt;]
    [0.05 rgb &lt;.8,.3,.6&gt;]
+
  [0.05 rgb &lt;.8,.3,.6&gt;]
    [0.10 rgb &lt;.3,.7,.9&gt;]
+
  [0.10 rgb &lt;.3,.7,.9&gt;]
    [0.15 rgb &lt;1,.7,.3&gt;]
+
  [0.15 rgb &lt;1,.7,.3&gt;]
    ...
+
  ...
    and so on
+
  [1.0 rgb &lt;.8,.2,.5&gt;]
 +
  }
 
</pre>
 
</pre>
 
+
<p>It is tedious to have to write the same things over and over just changing the index value and the values in the vector, even if you use copy-paste to copy the lines.</p>
</p>
+
<p>There is also one very big problem here: If you ever want to add a new color to the color map or remove a color, you would have to renumber all the indices again, which can be extremely tedious and frustrating.</p>
<p>It is tedious to have to write the same things over and over just changing
+
<p>Wouldn't it be nice to automate the creation of the color map so that you only have to write the vectors and that's it?</p>
the index value and the values in the vector (even if you use copy-paste to
+
<p>Well, you can. Using a while-loop which reads an array of vectors:</p>
copy the lines).
 
 
 
</p>
 
<p>There is also one very big problem here: If you ever want to add a new
 
color to the color map or remove a color, you would have to renumber all
 
the indices again, which can be extremely tedious and frustrating.
 
 
 
</p>
 
<p>Would not it be nice to automatize the creation of the color map so that
 
you only have to write the vectors and that is it?
 
 
 
</p>
 
<p>Well, you can. Using a while-loop which reads an array of vectors:
 
 
 
 
<pre>
 
<pre>
 
#declare MyColors = array[20]
 
#declare MyColors = array[20]
 
   {  &lt;.1,1,.6&gt;, &lt;.8,.3,.6&gt;, &lt;.3,.7,.9&gt;,
 
   {  &lt;.1,1,.6&gt;, &lt;.8,.3,.6&gt;, &lt;.3,.7,.9&gt;,
       &lt;1,.7,.3&gt;, ...
+
       &lt;1,.7,.3&gt;, ... , &lt;.8,.2,.5&gt;
 
   }
 
   }
  
 
...
 
...
  
  color_map
+
color_map {
  {  #declare LastIndex = dimension_size(MyColors, 1)-1;
+
  #declare LastIndex = dimension_size(MyColors, 1)-1;
      #declare Index = 0;
+
  #declare Index = 0;
      #while(Index &lt;= LastIndex)
+
  #while(Index &lt;= LastIndex)
  
        [Index/LastIndex rgb MyColors[Index]]
+
    [Index/LastIndex rgb MyColors[Index]]
  
        #declare Index = Index + 1;
+
    #declare Index = Index + 1;
      #end
+
  #end
 
   }
 
   }
 
</pre>
 
</pre>
 
+
<p>Now it is easy to add, remove or modify colors in your color map. Just edit the vector array, remembering to change its size number accordingly, and the while-loop will automatically calculate the right values and create the color map for you.</p>
</p>
 
<p>Now it is easy to add, remove or modify colors in your color map. Just
 
edit the vector array (remembering to change its size number accordingly)
 
and the while-loop will automatically calculate the
 
right values and create the color map for you.
 
</p>
 
  
 
===SDL tutorial: A raytracer===
 
===SDL tutorial: A raytracer===
  
===Introduction===
+
====Introduction====
 
<p>A raytracer made with POV-Ray sounds really weird, doesn't it? What is it
 
<p>A raytracer made with POV-Ray sounds really weird, doesn't it? What is it
 
anyways? POV-Ray is already a raytracer in itself, how can we use it
 
anyways? POV-Ray is already a raytracer in itself, how can we use it
Line 766: Line 447:
 
POV-Ray's raytracing part to just get the image on screen.</p>
 
POV-Ray's raytracing part to just get the image on screen.</p>
  
<p>What obscure idea could be behind this weirdness (besides a very serious
+
<p>What obscure idea could be behind this weirdness? Why do not just use POV-Ray itself to raytrace the spheres a lot faster and that is it?</p>
case of YHBRFTLW...)? Why do not just use POV-Ray itself to raytrace the
 
spheres a lot faster and that is it?</p>
 
  
 
<p>The idea is not speed nor quality, but to show the power of the POV-Ray SDL.
 
<p>The idea is not speed nor quality, but to show the power of the POV-Ray SDL.
Line 789: Line 468:
 
knowledge. Also more advanced users may get some new info from it.</p>
 
knowledge. Also more advanced users may get some new info from it.</p>
  
<p class="Note"><strong>Note:</strong> in some places some mathematics is needed, so you would better not
+
<p class="Note"><strong>Note:</strong> In some places some mathematics is needed, so you would better not
 
be afraid of math.</p>
 
be afraid of math.</p>
  

Latest revision as of 14:27, 16 December 2016

This document is protected, so submissions, corrections and discussions should be held on this documents talk page.


Making Animations

Do Not Use Jitter Or Crand

One last piece of basic information to save frustration. Because jitter is an element of anti-aliasing, we could just as easily have mentioned this under the INI file settings section, but there are also forms of anti-aliasing used in area lights, and the new atmospheric effects of POV-Ray, so now is as good a time as any.

Jitter is a very small amount of random ray perturbation designed to diffuse tiny aliasing errors that might not otherwise totally disappear, even with intense anti-aliasing. By randomizing the placement of erroneous pixels, the error becomes less noticeable to the human eye, because the eye and mind are naturally inclined to look for regular patterns rather than random distortions.

This concept, which works fantastically for still pictures, can become a nightmare in animations. Because it is random in nature, it will be different for each frame we render, and this becomes even more severe if we dither the final results down to, say 256 color animations (such as FLC's). The result is jumping pixels all over the scene, but especially concentrated any place where aliasing would normally be a problem (e.g., where an infinite plane disappears into the distance).

For this reason, we should always set jitter to off in area lights and anti-aliasing options when preparing a scene for an animation. The (relatively) small extra measure quality due to the use of jitter will be offset by the ocean of jumpies that results. This general rule also applies to any truly random texture elements, such as crand.

INI File Settings

Okay, so we have a grasp of how to code our file for animation. We know about the clock variable, user declared clock-relative variables, and the phase keyword. We know not to jitter or crand when we render a scene, and we are all set build some animations. Alright, let's have at it.

The first concept we will need to know is the INI file settings, Initial_Frame and Final_Frame. These are very handy settings that will allow us to render a particular number of frames and each with its own unique frame number, in a completely hands free way. It is of course, so blindingly simple that it barely needs explanation, but here is an example anyway. We just add the following lines to our favorite INI file settings

  Initial_Frame = 1
  Final_Frame = 20

and we will initiate an automated loop that will generate 20 unique frames. The settings themselves will automatically append a frame number onto the end of whatever we have set the output file name for, thus giving each frame an unique file number without having to think about it. Secondly, by default, it will cycle the clock variable up from 0 to 1 in increments proportional to the number of frames. This is very convenient, since, no matter whether we are making a five frame animated GIF or a 300 frame MPEG sequence, we will have a clock value which smoothly cycles from exactly the same start to exactly the same finish.

Next, about that clock. In our example with the rolling ball code, we saw that sometimes we want the clock to cycle through values other than the default of 0.0 to 1.0. Well, when that is the case, there are setting for that too. The format is also quite simple. To make the clock run, as in our example, from 0.0 to 2.0, we would just add to your INI file the lines

Initial_Clock = 0.0
Final_Clock = 2.0

Now, suppose we were developing a sequence of 100 frames, and we detected a visual glitch somewhere in frames, say 51 to 75. We go back over our code and we think we have fixed it. We would like to render just those 25 frames instead of redoing the whole sequence from the beginning. What do we change?

If we said make Initial_Frame = 51, and Final_Frame = 75, we are wrong. Even though this would re-render files named with numbers 51 through 75, they will not properly fit into our sequence, because the clock will begin at its initial value starting with frame 51, and cycle to final value ending with frame 75. The only time Initial_Frame and Final_Frame should change is if we are doing an essentially new sequence that will be appended onto existing material.

If we wanted to look at just 51 through 75 of the original animation, we need two new INI settings

Subset_Start_Frame = 51
Subset_End_Frame = 75

Added to settings from before, the clock will still cycle through its values proportioned from frames 1 to 100, but we will only be rendering that part of the sequence from the 51st to the 75th frames.

This should give us a basic idea of how to use animation. Although, this introductory tutorial does not cover all the angles. For example, the last two settings we just saw, subset animation, can take fractional values, like 0.5 to 0.75, so that the number of actual frames will not change what portion of the animation is being rendered. There is also support for efficient odd-even field rendering as would be useful for animations prepared for display in interlaced playback such as television (see the reference section for full details).

With POV-Ray 3 now fully supporting a complete host of animation options, a whole fourth dimension is added to the raytracing experience. Whether we are making a FLIC, AVI, MPEG, or simply an animated GIF for our web site, animation support takes a lot of the tedium out of the process. And do not forget that phase and clock can be used to explore the range of numerous texture elements, as well as some of the more difficult to master objects (hint: the julia fractal for example). So even if we are completely content with making still scenes, adding animation to our repertoire can greatly enhance our understanding of what POV-Ray is capable of. Adventure awaits!

While-loop tutorial

Usually people who have never programmed have great difficulties understanding how simple while-loops work and how they should be used. When you get into nested loops, the problem is even worse.

Sometimes even people who have programmed a bit with some language get confused with POV-Ray's while-loops. This usually happens when they have only used a for-loop which in itself has an index variable which is often incremented automatically.

What a while-loop is and what it is not

A while-loop in POV-Ray is just a control structure which tells POV-Ray to repeat a command block while the specified condition is true.

The while-loop syntax is as follows:

#while(condition)
  ...
#end

The commands between #while and #end are run over and over as long as the condition evaluates to true.

A while-loop is not a for-loop nor any kind of loop which has an index variable that may be incremented automatically with each iteration.

The while loop does not care what the conditions are between the parentheses as long as they evaluate to some value, nor what the block between #while and #end contains. It will just execute that block until the condition becomes false.

The while-loop does not do anything else. You can think of it as a "simple" loop, which does not do anything automatically. This is not necessarily a bad thing.

How does a single while-loop work?

The while loop works like this:

  1. If the condition between the parentheses evaluates to false, jump to the command after the #end statement. If the condition evaluates to true, just continue normally.
  2. At the #end statement jump to the #while statement and start again.

That is:

  • When POV-Ray gets to the #while statement it evaluates the condition between parentheses.
  • If the statement evaluated as true then it will just continue normally with the next command.
  • If the statement evaluated as false, POV-Ray will skip the entire body of the loop and continue with the command after the #end statement.
  • At an #end statement POV-Ray will just jump back to the corresponding #while statement, and will conditionally execute the commands, if the condition evaluates true.

Note that nowhere there is any mention about any index variable or anything else that could be used to automatically end the loop. As said, it is just a "simple" loop that continues forever if necessary, only testing the statement between the parentheses, and it is not interested in what it is, only in its evaluated value.

Although one could easily think that this kind of simple loop is bad, and it should be more intelligent, the fact is that this kind of simple loop is actually a lot more flexible and versatile. It allows you to make things not possible or very difficult to do with an intelligent for-loop with automatic index variables.

How do I make a while-loop?

It depends on what you are trying to accomplish.

The most common usage is to use it as a simple for-loop, that is, a loop which loops a certain number of times, with an index value getting successive values (for example 1, 2, 3, ..., 10).

For this you need to first declare your index identifier with the first value.

#declare Index = 1;

If you want to loop 10 times, remember how the condition worked: The while-loop repeats as long as the condition is true. So it should loop as long as our 'Index' identifier is less or equal to 10

#while(Index <= 10)

When the value of 'Index' is 11 the loop ends, as it should.

We only have to add 1 to 'Index' at the end of each loop

#declare Index = 1;
#while(Index <= 10)

  (some commands here)

  #declare Index = Index + 1;
#end

The incrementation before the #end is important. If we do not do it, 'Index' would always have the value 1 and the loop would go forever since 1 is always less or equal to 10.

What happens here?

  1. First POV-Ray sets the value 1 to 'Index'.
  2. Then it sees the #while statement and evaluates what is between the parentheses: Index <= 10
  3. As 'Index' has the value of 1 and 1 <= 10, the condition evaluates to true.
  4. So, it just continues normally, and executes the commands following the #while statement, as noted in the above example as (some commands here).
  5. Then it arrives normally to the last #declare command in the block. This causes the value 2 to be assigned to 'Index'.
  6. Now it arrives the the #end command and so it just jumps to the #while.
  7. After that it executes the steps 2-6 again because 2 is also less or equal to 10.
  8. After this has been done 10 times, the value 11 is assigned to 'Index' in the last command of the block.
  9. Now, when POV-Ray evaluates the condition it sees that it is false, because 11 is not less or equal to 10. This causes POV-Ray to jump to the command after the #end statement.
  10. The net effect of all this is that POV-Ray looped 10 times and the 'Index' variable was assigned successive values from 1 to 10 along the way.

If you read carefully the above description you will notice that the looping is done in a quite simple way, that is, there is no higher logic hidden inside the loop structure. In fact, POV-Ray does not have the slightest idea how many times the loop is executed and what variable is used to count the loops. It just follows orders.

The higher logic in this type of loop is in the combination of commands we wrote. The effect of this combination is that the loop works like a simple for-loop in most programming languages (like BASIC, etc).

What is a condition and how do I make one?

A condition is an expression that evaluates to a boolean value (ie. true or false) and is used in POV-Ray in #while loops and #if statements.

A condition is mainly a comparison between two values, although there are also some other ways of making a condition, that is not important now.

For example:

1 < 2  is true
1 > 2  is false
1 = 1  is true
1 = 2  is false

Usually it makes no sense to make comparisons like those. However, when comparing identifiers with some value or two identifiers together it starts to be very useful. Consider this:

#if(version < 3.1)
  #error "Wrong version!"
#end

If the identifier called 'version' has a value which is less than 3.1 the #error line will be executed. If 'version' has a value which is 3.1 or greater, the #error line is just skipped.

You can combine conditions together with the boolean operators & (and) and | (or). You can also invert the value of a condition with ! (not).

For example, if you want something to be done when 'a' is less than 10 and 'b' is greater or equal to 20, the condition would be:

a<10 & b>=20

For more information about these comparison operators, see the Operators section of the POV-Ray documentation.

What about loop types other than simple for-loops?

As POV-Ray does not care what the condition is and what we are using to make that condition, we can use the while-loop in many other ways.

For example, this is a typical use of the while-loop that is not just a simple for-loop:

#declare S = seed(0);
#declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
#while(vlength(Point) > 1)
  #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
#end

We take a random point between <-1, -1, -1> and <1, 1, 1> and if it is not inside the unit sphere take another random point in that range until we get a point inside the unit sphere.

This is not an unrealistic example since it is very handy, and we can plainly see, this looks nothing like an ordinary for-loop.

  • It does not have any 'index' value which gets consecutive values during the loop.
  • We do not know how many times it will loop. In this case it loops a random number of times.
  • Usually for-loops are used to place or create a series of objects. For each iteration another instance of that object is created. Here, however, we are only interested in the value that results after the loop, not the values inside it.

As we can see, a while-loop can also be used for a variety of tasks, for instance, to calculate a value or some values until the result is inside a specified range.

By the way, there is a variant of this kind of loop where the task would be to calculate a value until the result is inside a specified range, but make only a certain number of tries. If the value does not get inside that range after that number of tries, stop trying. This is used when there is a possibility for the loop for going on forever.

In the above example about the point inside the unit sphere we do not need this because the random point will surely hit the inside of the sphere at some time. In some other situations, however, we cannot be so sure.

In this case we need a regular index variable to count the number of loops. If we reach a predetermined number of iterations, then we stop.

Suppose that we wanted to modify our point searching program to be completely safe and to try only up to 10 times. If the point does not hit the inside of the sphere after 10 tries, we just give up and use the point <0,0,0>.

#declare S = seed(0);
#declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
#declare Index = 1;
#while(Index <= 10 & vlength(Point) > 1)
  #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
  #declare Index = Index + 1;
#end

#if(vlength(Point) > 1)
  #declare Point = <0,0,0>
#end

What did we do?

  • We added an 'Index' value which counts the amount of loops gone so far. It is quite similar to the index loop of a simple for-loop.
  • We added an extra condition to the while-loop: Besides testing that the point is outside the unit sphere it also tests that our index variable has not bailed out. So now there are two conditions for the loop to continue: The 'Index' value must be less or equal to 10 and the 'Point' has to be outside the unit sphere. If either one of them fails, the loop is ended.
  • Then we check if the point is still outside the unit sphere. If it is, we just take <0,0,0>.

Sometimes it is not convenient to make the test again in the #if statement. There is another way of determining whether the loop bailed out without successful termination. Since the loop ends when the 'Index' gets the value 11, we can use this to test the successfulness of the loop

#if(Index = 11)
  (loop was not successful)
#end

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 in creating a 2D array of objects, that is rows and columns of objects. For example if you want to create a 10x20 array of spheres in your scene, a nested loop is up to the task.

There is 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 is 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 is 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 is a common mistake for beginners to break this structure. For example it is common to declare the 'Index2' before the first #while. This breaks the for-loop structure and thus does not work. If you follow step by step what POV-Ray does, as explained earlier, you will see why it does not work. Do not 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

Notice 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 is no reason why we should limit ourselves to just two nested loops. There is virtually no limit how many loops you can nest. For example, if we wanted to create a box-shape filled by spheres rows, columns 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.

Mixed-type nested loops

It is perfectly possible to put a for-loop inside a non-for-loop or vice-versa. Again, you just have to be careful, with experience it gets easier.

For example, suppose that we want to create 50 spheres which are randomly placed inside the unit sphere.

So the distinction is clear: First we need a loop to create 50 spheres, a for-loop type suffices, and then we need another loop inside it to calculate the location of the sphere. It will look like this:

#declare S = seed(0);
#declare Index = 1;
#while(Index <= 50)

   #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
   #while(vlength(Point) > 1)
      #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
   #end

   sphere { Point, .1 }

   #declare Index = Index + 1;
#end

There are some important things to note in this specific example:

  • Although this is a nested loop, the sphere is not created in the inner loop but in the outer one. The reason is clear: We want to create 50 spheres, so the sphere creation has to be inside the loop that counts to 50. The inner loop just calculates an appropriate location.
  • The seed value 'S' is declared outside all the loops although it is used only in the inner loop. Can you guess why? Putting it inside the outer loop would have caused an undesired result: Which one?

Other things to note

There is no reason why the index value in your simple for-loop should step one unit at a time. Since the while-loop does not care how the index changes, you can change it in whichever way you want. For example:

#declare Index = Index - 1;   // Decrements the index (be careful with the while loop condition)
#declare Index = Index + 0.2; // Increases by steps of 0.2
#declare Index = Index * 2;   // Doubles the value of the index at each step.

Note: Be careful where you put your while-loop.

The example below illustrates a very common mistake:

#declare Index = 1;
#while(Index <= 10)
   blob
   {  threshold 0.6
      sphere { <Index, 0, 0>, 2, 1 }
   }
   #declare Index = Index + 1;
#end

You will probably immediately see the problem.

This code creates 10 blobs with one component each. It does not seem to make much sense. Most probably the user wanted to make one blob with 10 components.

Why did this mistake happen? It may be that the user thought that the while-loop must be the outermost control structure and did not realize that while-loops can be anywhere. For example, inside objects to create subcomponents.

The correct code is, of course:

blob
{  threshold 0.6

   #declare Index = 1;
   #while(Index <= 10)

      sphere { <Index, 0, 0>, 2, 1 }

      #declare Index = Index + 1;
   #end
}

The essential difference here is that it is only the sphere code which is run 10 times instead of the whole blob code. The net result is the same as if we had written the sphere code 10 times with proper values of 'Index'.

Be also careful with the placement of the braces. If you put them in the wrong place you can end up accidentally repeating an opening or a closing brace 10 times. Again, a proper indentation usually helps a lot with this, as seen in the above example.

Tip: You can use while-loops in conjunction with arrays to automate the creation of long lists of elements with differing data.

Imagine that you are making something like this:

color_map {
  [0.00 rgb <.1,1,.6>]
  [0.05 rgb <.8,.3,.6>]
  [0.10 rgb <.3,.7,.9>]
  [0.15 rgb <1,.7,.3>]
  ...
  [1.0 rgb <.8,.2,.5>]
  }

It is tedious to have to write the same things over and over just changing the index value and the values in the vector, even if you use copy-paste to copy the lines.

There is also one very big problem here: If you ever want to add a new color to the color map or remove a color, you would have to renumber all the indices again, which can be extremely tedious and frustrating.

Wouldn't it be nice to automate the creation of the color map so that you only have to write the vectors and that's it?

Well, you can. Using a while-loop which reads an array of vectors:

#declare MyColors = array[20]
   {  <.1,1,.6>, <.8,.3,.6>, <.3,.7,.9>,
      <1,.7,.3>, ... , <.8,.2,.5>
   }

...

color_map {
  #declare LastIndex = dimension_size(MyColors, 1)-1;
  #declare Index = 0;
  #while(Index <= LastIndex)

     [Index/LastIndex rgb MyColors[Index]]

     #declare Index = Index + 1;
   #end
   }

Now it is easy to add, remove or modify colors in your color map. Just edit the vector array, remembering to change its size number accordingly, and the while-loop will automatically calculate the right values and create the color map for you.

SDL tutorial: A raytracer

Introduction

A raytracer made with POV-Ray sounds really weird, doesn't it? What is it anyways? POV-Ray is already a raytracer in itself, how can we use it to make a raytracer? What the...?

The idea is to make a simple sphere raytracer which supports colored spheres (with diffuse and specular lighting), colored light sources, reflections and shadows with the POV-Ray SDL (Scene Description Language), then just render the image created this way. That is, we do not use POV-Ray itself to raytrace the spheres, but we make our own raytracer with its SDL and use POV-Ray's raytracing part to just get the image on screen.

What obscure idea could be behind this weirdness? Why do not just use POV-Ray itself to raytrace the spheres a lot faster and that is it?

The idea is not speed nor quality, but to show the power of the POV-Ray SDL. If you know how to make such a thing as a raytracer with it, we can really grasp the expressive power of the SDL.

The idea of this document is to make a different approach to POV-Ray SDL teaching. It is intended to be a different type of tutorial: Instead of starting from the basics and give simple and dumb examples, we jump right into a high-end SDL code and see how it is done. However, this is done in a way that even beginners can learn something from it.

Another advantage is that you will learn how a simple sphere raytracer is done by reading this tutorial. There are lots of misconceptions about raytracing out there, and knowing how to make one helps clear most of them.

Although this tutorial tries to start from basics, it will go quite fast to very "high-end" scripting, so it might not be the best tutorial to read for a completely new user, but it should be enough to have some basic knowledge. Also more advanced users may get some new info from it.

Note: In some places some mathematics is needed, so you would better not be afraid of math.

If some specific POV-Ray SDL syntax is unclear you should consult the POV-Ray documentation for more help. This tutorial explains how they can be used, not so much what is their syntax.


The Phase Keyword The idea and the code


This document is protected, so submissions, corrections and discussions should be held on this documents talk page.