Creating a Ray Traced Animation with Pov-Ray

This image is based off a simple algorithm that randomly picks a pixel on the screen and if another pixel is adjacent to it, it is plotted. If not, another pixel is picked. I was able to extend this idea to work in 3D by writing a program that picks random points in a 3 dimensional array and instead of plotting pixels to the screen, it writes sphere coordinates to a POV-Ray include file. The molecule object is stored in that file while the camera, rotation for the object, textures and other scene elements were stored in the animation file.

Here is the main procedure that creates the object:

procedure molecule;
  var
    x, y, z, i: integer;
  begin
    for x := 0 to 30 do  {zeros out our 3 dimensional array of booleans}
      for y := 0 to 30 do
        for z := 0 to 30 do
          a[x, y, z] := false;

    a[15, 15, 15] := true;    {sets a "seed" in the middle}
    writepiece(15, 15, 15);   {a procedure that writes "sphere{x,y,z,1}"}
    i := 0;
    repeat
      i := i + 1;
      repeat
        x := abs(random mod 29) + 1;  {picks random points in the array}
        y := abs(random mod 29) + 1;
        z := abs(random mod 29) + 1;
      until vertices(x, y, z);  {a function that determines if another sphere is nearby}
      a[x, y, z] := true;       {if there is, plot this sphere here}
      writepiece(x, y, z);
    until i > 300;      {we don't want any more than 300 spheres}
  end;

"a" is a 3 dimensional array of booleans. This will serve as our 3D "screen." First, we clear it out and set one "seed" sphere into the middle. If we didn't do this, no spheres would ever be plotted. We then pick a random coordinate and pass the values to the function called vertices(), which determines if there are any other spheres along the eight vertices of the cubic 3D "pixel." This means a sphere can be almost anywhere close by. If the point passes this test, it is added into the array by setting the array indices to true. We then write the values into the file via the writepiece() procedure. We keep doing this until we have 300 spheres and the object will resemble a large molecule.

It wasn't long after I rendered Molecule that I discovered a new algorithm. This time, a random 3D point is picked and if it happens to be a certain distance from the origin, it is plotted. What happens is that spheres are plotted on the surface of a sphere. I wrote a program that would create the include file for POV-Ray. Other scene elements such as rotation, camera angle and textures were stored in the animation file. Here is the main procedure that creates the object:

procedure atom;
  var
    x, y, z: real;
    i: integer;
  const
    e = 0.1;
  begin
    repeat
      x := random / 10000;
      y := random / 10000;
      z := random / 10000;
      if (x * x + y * y + z * z - 9 < e) and (x * x + y * y + z * z - 9 > -e) then
        begin
          writepiece(x, y, z);
          i := i + 1;
        end;
    until i = 300;
  end;

This procedure simply picks 3 coordinates and uses the pythagorean formula to calculate the distance to the origin. If the point is within 3 units, i.e. it is on the surface of a sphere of radius three, a sphere is written at those coordinates. The constant e is supposed to represent epsilon, which is the margin of error the coordinate can be in. So the distance squared can be within 9-e and 9+e.

To create the animation, I used trig functions to control the x, y and z coordinates of the camera. This made the camera circle the object while moving up and down like a sine wave. The objects rotate, grow and pulsate. The sky is also advancing and the water is rippling. The animation was generated frame by frame and combined into a quicktime movie.

Because Pov-Ray version 2 did not come with any built in trigonometric functions, I had to completly write my own. Digging through my calculus book, I discovered the method using a taylor series to calculate the values for sine and cosine using algebraic methods that PoVRay can handle. I created a file that would simply act as the sine and cosine functions by defining variables sin_x and cos_x. I wrote a program that would create the output for this trig include file to save myself some writing. Note that the actual method for calculating trigonometric functions involves an infinite sum, and the error of the function increases as the x values get larger because there is a finite number of additions to do. But this created a fairly close approximation.

The values of sin_x and cos_x were used to calculate the camera position and rotation with x corresponding to the frame number in the animation sequence. I wanted frame one to correspond with 0 radians of angle and the last frame to correspond to 2* radians of angle, which would cause all values to increase then decrease back to their original values at frame one so the animation could loop.

Once the two different movies were complete, I took a still from both animations and used a morphing program to morph the two sequences together. I then used a video sequencer to combine all three quicktime movies resulting in one smoothly flowing continuously looping animation.


Return to Main Page