Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

Have a Merry Scripting Christmas with Persistence of Vision

Jerry Stratton, December 25, 2019

Some of the best Christmas mornings I remember are mornings when I holed myself away and built things. On earlier Christmases, it could have been Legos, or off-brand erector sets, or a model train. Later, it might have been building characters or adventures using the new Dungeons and Dragons Basic or Expert boxed set I found under the tree.

When sitting at the computer, every day was Christmas, and in many ways it still is. As you can see from the majority of this blog, I’m still finding joy in the ASCII art script. So why not a touch more joy on Christmas morning? Consider this my erector set gift to you.

Except for this image, all of the ASCII art created using the asciiArt script in 42 Astounding Scripts came from photographs or drawings. That is, a human hand was involved in its creation.

This Christmas image, on the other hand, was nearly completely scripted. Obviously, the version with Linus’s Bible quote over the Christmas scene came from the asciiArt script, but the Christmas scene itself came from the Persistence of Vision raytracer. The only hand-placed part of the image was the phrase “Merry Christmas” in the upper left.

Persistence of Vision is a lot of fun to play with, Christmas morning or any morning. Or, as was often the case for me (and still often is) late into the night.

Remember to install brew and then “brew install povray” as described in the bubble cake example if you haven’t already. To create an image from this POV-Ray script file, run the povray program on it, as you would any other command-line script or program.

  • $ povray Christmas.pov

This will create, by default, an 800 by 600 PNG image with the same filename as the .pov file but with the extension .png. In this case, if you name the file “Christmas.pov” as I did, the file will come out “Christmas.png”.

You can adjust the width and/or height using the Width= and Height= command line options.

  • #to double the dimensions
  • $ povray Christmas.pov Width=1600 Height=1200
  • #for a 2.39:1 widescreen image:
  • $ povray Christmas.pov Width=1600 Height=670
  • #for a Facebook-friendly ratio to share with your friends:
  • $ povray Christmas.pov Width=1200 Height=628

If the ratio between the width and height remain the same, the image looks the same as well, other than being higher or lower quality depending on whether it has bigger or smaller dimensions. If the ratio changes, then the image changes as well. As in a movie scene, a wider ratio shows more off to the sides, and a taller ratio shows more top and bottom.

The Persistence of Vision code is very simple.

[toggle code]

  • //A simple Christmas scene
  • //Jerry Stratton astoundingscripts.com/merry
  • #include "colors.inc"
  • #include "textures.inc"
  • #declare aspectRatio = image_width/image_height;
  • camera {
    • location <0,0,-120>
    • look_at <0,0,0>
    • right x*aspectRatio
  • }
  • //stars in the sky
  • light_source { <1000,1000,-2000> White*0.2 }
  • light_source { <15000,15000,50000> White }
  • sky_sphere {
    • pigment {
      • bozo
      • color_map {
        • [0.0 White*3]
        • [0.2 Black]
        • [1.0 Black]
      • }
      • scale .001
    • }
  • }
  • //the snow-covered ground
  • height_field {
    • png "plasma3.png"
    • smooth
    • translate <-0.5,0,-0.5>
    • scale <1400,100,1000>
    • translate y*-210
    • pigment { SkyBlue }
    • normal {
      • crackle 0.2
      • scale 2
    • }
    • finish { Shiny }
  • }
  • //the red cross
  • union {
    • box {
      • <-.2,0,-.2>,<.2,2,.2>
    • }
    • box {
      • <-.6,1.2,-.2>,<.6,1.6,.2>
    • }
    • scale 240
    • rotate y*40
    • pigment { color Red }
    • translate <280,-250,640>
  • }
  • //trees
  • #declare tree = object {
    • cone {
      • <0,0,0>, 96, <0,240,0>,0
      • pigment { color Green }
    • }
  • }
  • union {
    • object { tree }
    • object { tree
      • translate <120,-30,120>
    • }
    • object { tree
      • translate <-120,0,140>
    • }
    • translate <-150,-170,380>
  • }

It consists of four items: a sky sphere, a height field for the ground, a cross, and a set of trees.

The Camera
Just as in the earlier example, the camera defines the direction from which we see the scene. This virtual camera is set up backward 120 units, looking straight down to the origin of <0,0,0>. Because I know I’m going to want to render this image at different sizes, and because it’s a good idea in general, I orient the camera using the aspect ratio of the image.
The stars in the sky
Every image has a light source, and in this case there are two, and they’re far away. There’s a dim one behind the camera, and a bright one far off in the sky, something like moonlight. The dim one is made dim by multiplying White by 0.2. There’s no difference between White*0.2 and 0.2—because White is <1,1,1>, both mean <0.2,0.2,0.2>—but the former reminds me what I’m doing. The stars themselves are a sky_sphere given a pseudo-random noise pattern (bozo) that looks pretty decent as stars. The stars are very bright in the sky field—they are literally whiter than white, by three times. The sky sphere’s pigment is white and black, and scaled very tiny to look like far away stars.
The snow-covered ground
A height field in Persistence of Vision takes an image and converts the colors of the image to heights in the scene. POV comes with a handful of predefined height fields, of which plasma3.png is one. Try commenting out the “smooth” keyword and rendering the image, and you’ll see the triangles that make up the mesh created by the values in plasma3.png. By smoothing and scaling up the height field, we end up with something that looks like rolling hills. And by giving it a shiny sky blue pigment, it looks like snow-covered hills.
The red cross
This is the simplest shape in the scene. It’s nothing more than two rectangular boxes, one long and one tall, joined into a cross shape. It is scaled up 240 times, rotated around the y axis (comment out the rotate y*40 line and you’ll see that the cross is now facing toward the camera), given the color red, and then moved to where in the scene I want it.
Trees
The trees are cones, given a straight green color. The one tree object is used three times to create a small grove of trees on the height field. Two of the trees are moved so that they’re not on top of each other, and then the entire grove is moved to where I want the trees in the scene.

Persistence of Vision renders these objects as if they actually existed in the scene as created. The cross, trees, and height field throw shadows from the light sources. Because the height field has been given a shiny finish, it reflects the light that’s shining on it from the stars. Even the sky sphere, though it isn’t obvious in this scene, curves around as if it were a sphere around the scene.

The scene can be made a lot more complex, and in fact this is one of the advantages of using a scripting language to create images. If you want more trees, add more of the trees you already have. You can reuse objects and entire scenes with different parts, such as by adding falling snow. I didn’t use the snow in the book because, besides being more complicated, the snow muddles up the ASCII art.

If you look closely at the ASCII version of the image, you’ll see a lens flare against one of the arms of the cross. I left that out of these examples because lens flares, like snow, are a more complex topic.

Even the text “Merry Christmas” could have been scripted if I’d felt like it. Add the following to the bottom of the script, and you’ll get MERRY CHRISTMAS in the upper left.

[toggle code]

  • //Merry Christmas!
  • union {
    • text {
      • internal 1 "MERRY"
      • .05, 0
      • translate <0,0,0>
    • }
    • text {
      • internal 1 "CHRISTMAS"
      • .05, 0
      • translate <-1.1,-1,0>
    • }
    • texture {
      • pigment { color Gold }
      • finish {
        • Shiny
        • ambient .4
      • }
    • }
    • scale 70
    • translate <0,180,400>
    • translate <-148*pow(aspectRatio,1.4),0,0>
  • }

This is the union of two text objects; one reads “MERRY” and the other “CHRISTMAS”. The Christmas text is translated left 1.1 units and down 1 unit, to center it below the Merry text. Then the entire thing is scaled 60 times and translated into the upper left. In order to get the text approximately at the upper left for all three of the aspect ratios, I did a rough formula based on the aspect ratio. It’s very rough—it isn’t likely to work well with other aspect ratios.

  1. <- POV photos
  2. Photograph titles ->