The POV-Ray Cyclopedia

One of the confusing things about POV-Ray are the seed() and rand() functions used to create random numbers. The main problem is that if you want a truly random number between 0 and 1, roll a bunch of dice and find their average value. This is not something computers can really do. Instead what they do is perform a calculation that expliots the word length of the computer to create a pseudo-random number.

What does pseudo-random mean? It means that the algorithm starts with one value and returns a number between 0 and 1. Then it takes the previous input and gives you another number. Since it always uses the previous input you end up getting a series of numbers with no easily discernable pattern to them. (Yes, this is a drastic oversimplification of random number generation.)

Since random number generator gives a string of predetermined numbers, the only way to "control" the numbers is to provide the initial number, which in RNG theory and in POV-Ray is called a seed. By declaring the same seed, you'll get the same series of numbers, which is good for testing, but not good for true unpredictability. For what POV-Ray needs to do, the built in seed and rand functions do fine.<\p>
Part Zero
The Basics of Random Number Generation

  In order to use random numbers in POV-Ray you first need to declare a variable to hold the seed() value, and then you need to use the rand() function on that variable. As in the following:

#declare firstSeed = seed(63981);
#delcare randomNumber = rand(firstSeed);

  So the variable randomNumber has a value between 0 and 1. It can return the value 0 but it will not actually return the value of 1. The 30 colored boxes in image 1 was generated with the following code:

#declare R1 = seed (34567);
#declare ucnt = 0;
#while (ucnt < 6 )
  #declare vcnt = 0;
  #while ( vcnt < 5 )
    box { <ucnt-3,-1,vcnt-2.5> <ucnt-2.1,1,vcnt-1.6>
          pigment { rgb <rand(R1),rand(R1),rand(R1)> } }
    #declare vcnt = vcnt +1;
  #end
  #declare ucnt = ucnt + 1;
#end

  Nothing too exciting, but it gave me a nice set of colors that I probably couldn't have come up with on my own. Here is where the advantage of using a user defined seed value comes in. I can take a look at my output, find acolor I like, then add a few lines of code and run the file again, and POV-Ray will tell me what color it is, and I can record it for later use. I'll come back to random color later.

  There are a few pitfalls with the POV-Ray random number code that fall under the "DUH" category. It's simple, and the user forgets to initialize the seed value, or tries to use #declare thisNumber = rand(4); and hopes to get a random number between 1 and 4. This won't work because the rand function can only accept certain kinds of input. It is also glib. The user probably wants a random integer between 1 and 4, but rand will provide a decimal number, and not an integer. You can't fix this error with rand() *4, either. At best you'd get a number between 0 and 3.99999... and not an integer at all.

30 Random Colors
1. 30 Random Colors
Part One
Random Integers

  To get random integers we need to add to the random function just a bit. To stick with the example, if we want to get a random number between 1 at 4, we need to take the take our random number from 0 to 1, multiply it by 4, take the integer part of it, and add 1:

#declare firstSeed = seed(63981);
#delcare randomNumber = int(rand(firstSeed)*4) + 1;
  We have to remember that rand() goes from 0 to 1, so the integer value of rand()*4 gives us a number between 0 and 3, and we want 1 to 4, so adding 1 takes care of it.

  Be careful with the parenthesis, because if you don't group them properly you will always get 0 as a random number:

int(rand(firstSeed)) * 4 + 1;
Will find the integer value of a number that can be between 0 and 1, so it always returns 0.

  What if you don't wan't to have a random number between 1 and something but a random integer between any two numbers? Simple. We generalize what we already know. Let's find a random number between 5 and 9, so we want to make a macro that will spit out 5, 6, 7, 8, or 9. There are five possible outputs, and we already know how to get one of five possible outputs, so we have the following:

#delcare randomNumber = int(rand(firstSeed)*(5)) + 5;
Which gives us values of 0 to 4, plus 5. Lets generalize even more:
#macro RandomInt(sd,mn,mx)
  (int(rand(sd)*(mx-mn+1)) + mn)
#end
The +1 might surprise you, but it's because we want integers, and not real numbers, that we have to add it. Going back to the 5 to 9 problem, there are 5 possible numbers we want, and to get them we need to multiply our random number by 6. When we look at finding random real numbers, and not integers, we can get rid of the +1.

  The sd parameter allows the user to use different seed streams, in case there are several being used at one time.

Part Two
Random Reals

  The random function gives us a real number, and that's just fine for now. In fact, it makes rand() a whole lot easier to deal with. I said we could make a simple macro, and here it is.

#macro RandomReal(sd,mn,mx)
  (rand(sd)*(mx-mn) + mn)
#end
This will give us a random number between mn and mx, and it will give use real numbers.

  You can cheat a random number to be high end or low end by taking the rand() result and raise it to a power before you do anything else:

 pow(rand(sd),0.5)*(mx-mn) + mn) // Numbers tend to be towards the higher bound
 pow(rand(sd),2)*(mx-mn) + mn) // Numbers tend to be towards the lower bound


Send feedback, or head back to the Cyclopedia.

Thanks for watching.