Sunday, December 26, 2010

POV-ray + Python - Scene Creation

Brief recap:  this recipe from the Python cookbook webpage is the basis for an api for POV-ray from Python.  I added an Object class to the api for more flexibility in manipulating pre-made POV-ray objects.

This final post in the POV-ray series deals with an attempt to create a scene.  I want to draw some pysanky eggs on a board with pegs in it for the eggs to stand on.

For the wood texture of the board I've used T_Wood10 from the POV-ray library.  This requires the inclusion of the library in the Python code:

file = pov.File('test5.pov', '', '')

test5.pov is my output file; and are my include files.

Because the api deals exclusively with text, the wood texture will have to be put in as a string literal complete with POV-ray's curly brackets:

testblock = pov.Box((-15, -6.50, -18), (15, -2.00, -3), 
    texture = '{T_Wood10}')

As for the scene itself:
This is good for illustrating the scene's design, but it's not very realistic.  The eggs look like they're wrapped in cellophane.  I tried introducing some focal blur:

cam = pov.Camera(location = (0, 5, -35), look_at = (0, 0, 2),
    focal_point = (0, 2, -10), aperture = 0.4, blur_samples = 20)

This looks more realistic, but blurry.  It would probably serve a remote corner of a scene better rather than the main object.

At this point it's really the nuances of POV-ray scene creation that will make a difference.  The purpose of this post and the last three was to show that you can do some fun things with POV-ray from Python.

Lastly, and just for fun, some wooden eggs (textures, T_Wood10 and T_Wood14):

Tuesday, December 21, 2010

Coding POV-ray in Python

My past two posts were basically on the same topic as this one.  The difference now is that I was able to write Python code as I would normally write it with functions, dictionaries, and loops and still come out with valid POV-ray code on the other end.  It's about a third of the length of the equivalent POV-ray code and, for me at least, easier to understand and read.

Here is the last part of the code that resulted in the scene of the three eggs below:

file = pov.File('test4.pov', '')
cam = pov.Camera(location = (-2, 3, -12), look_at = (0, 0, 2))
sorokolines = makesorokolines()testblock = makeredwedges()
testblockred = pov.Object(testblock, RED)
testblock = makeblackwedges()
testblockblack = pov.Object(testblock, BLACK)
test = pov.Union(testblockred, testblockblack, sorokolines)
test1 = pov.Object(test, translate = (2, 2, 0))
test2 = pov.Object(test, translate = (-2, -2, 0))
test3 = pov.Object(test, translate = (-6, 2, 0))
file.write(cam, test1, test2, test3, light1, light2, light3, light4, light5)

Now that I've proven to myself that I can code this in Python, I'd like to try something more involved like putting the eggs on a surface with a texture.

Thanks for having a look.

Monday, December 13, 2010

More POV-ray

Since last time I've had some success porting POV-ray code to Python code based on this recipe by Simon Burton.

To briefly recap, I'm trying to reproduce this egg with Python code:

Since my first attempt, this is how far I've gotten:
Basically, the lines; I've made them a bit thicker to emphasize them.  I'm still working on getting the camera and look at values set to coincide with the main axes.

The pictures are all well and good, but what's pretty exciting is that I made the second one using the API from the recipe.  Further, I was able to expand on the recipe by adding an Object class:

class Object(Item):
  def __init__(self, *opts, **kwargs):
    Item.__init__(self, "object", (), opts, **kwargs)

This was really simple; I just copied what Simon Burton had done with the other classes.  Still, it opened up a lot of possibilities for twirling, flipping, and coloring elements once they're constructed.  For example, the code for the dividing lines above is (I've skipped the egg shape code for brevity):

white = pov.Texture(pov.Pigment(color = (1.0, 1.0, 1.0)),
    pov.Finish(phong = redphng, reflection = redrflct))
horizontaldividingline = pov.Box((-3, 2.15, -3), (3, 2.25, 3), white)
verticaldividingline = pov.Box((-0.05, -1, -3), (0.05, 7, 3), white)

# vectors for dividing lines
# down on y axis
movedown = (0, -2.2, 0)
# up on y axis
mvup = (0, 2.2, 0)
# flip right around z axis
flprt = (0, 0, -52.5)

# scale - same in all directions (2)
scal = (2, 2, 2)

# turn for display
trn15back = (0, -15, 0)

planes = [horizontaldividingline, verticaldividingline]

# vertical planes
turn = 45
for counter in range(3):
    plane = pov.Object(verticaldividingline, rotate = (0, turn, 0))
    turn += EIGHTHTURN

# for dividing lines at angle to horizontal
flprtdivlinepre = pov.Object(horizontaldividingline,
    translate = movedown, rotate = flprt)
flprtdivline = pov.Object(flprtdivlinepre, translate = mvup)

turn = 90
for counter in range(3):
    plane = pov.Object(flprtdivline, rotate = (0, turn, 0))
    turn += QUARTERTURN

sorokoplanes = pov.Union(*planes)

eggwhite = pov.Object(unionegg, white, scale = scal)

sorokolines = pov.Intersection(eggwhite, sorokoplanes)

sorokotest = pov.Object(sorokolines, translate = (0, -2.75, 0), rotate = trn15back)

The egg design is very symmetrical and lends itself to repetition.  I tried to use this to my advantage with the two loops.  The list unpacking also compresses the code a bit.

Next on the agenda is placing code in functions and classes.  This would allow for making multiple eggs of different colors with a single code call.

Sunday, December 5, 2010


I messed around with POV-ray a bit about five years ago and recently tried to resurrect some of that code.

There's a recipe for a POV-ray - Python API by Simon Burton out on ActiveState that I wanted to try.

Here is the shape I was trying to re-create with the Python API:
Literally, an Easter egg, a bit involved, but not overly complex.  The egg shape is borrowed from Friedrich Lohmüller's POV-ray site.

There is a simple example in the API which I've slightly modified to make a partially lit sphere:

# renamed recipe as pypov
import pypov as pov

file = pov.File('test2.pov', '')
cam = pov.Camera(location = (0, 1, -5), look_at = (0, -0.5, 2))
sphere = pov.Sphere((0, 0, 0), 1.5, pov.Texture(pov.Pigment(color = 'Blue')))
light = pov.LightSource((2, 4, -3), color = 'White')
file.write(cam, sphere, light)

This, after its output is run through POV-ray, yields this:
It won't win any animation awards, but it's pretty nonetheless.

The code for Lohmüller's egg shape looks like this:

# renamed recipe as pypov
import pypov as pov

file = pov.File('test3.pov', '')
cam = pov.Camera(location = (0, 1, -5), look_at = (0, -0.5, 2))
sphereupper = pov.Sphere((0, 0, 0), 1.0, pov.Texture(pov.Pigment(color = 'Blue')), scale = (1, 1.55, 1))
slabupper = pov.Box((-1, -1.55, -1), (1, 0, 1))
diffupper = pov.Difference(sphereupper, slabupper)
spherelower = pov.Sphere((0, 0, 0), 1.0, pov.Texture(pov.Pigment(color = 'Blue')), scale = (1, 1.15, 1))
slablower = pov.Box((-1, 0, -1), (1, 1.15, 1))
difflower = pov.Difference(spherelower, slablower)
union = pov.Union(difflower, diffupper, translate = (0, 0.55, 0), scale = 1.0)
light = pov.LightSource((2, 4, -3), color = 'White')
light2 = pov.LightSource((-2, -4, -3), color = 'White')
file.write(cam, union, light, light2)

and the output looks like this:

That is about as far as I got with the Python API.  The problems I was having were related to trying to shoehorn my POV-ray code into the API.  I added an Object class for the purpose of assigning attributes to predefined shapes.  The problem there is that you can't use the same keyword more than once (translate, then  rotate, then translate again).

Going forward I plan to work with simpler shapes (merging two parts instead of 50 or so).  Also, I'll need to leverage what the API offers against working within its limitations.  It will not be a one to one code translation between POV-ray and Python.