Here is a relatively simple framework for making povray files from your favourite programming language, python. It's good for creating structured/mathematical scenes and animations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | import sys, os
class File:
def __init__(self,fnam="out.pov",*items):
self.file = open(fnam,"w")
self.__indent = 0
self.write(*items)
def include(self,name):
self.writeln( '#include "%s"'%name )
self.writeln()
def indent(self):
self.__indent += 1
def dedent(self):
self.__indent -= 1
assert self.__indent >= 0
def block_begin(self):
self.writeln( "{" )
self.indent()
def block_end(self):
self.dedent()
self.writeln( "}" )
if self.__indent == 0:
# blank line if this is a top level end
self.writeln( )
def write(self,*items):
for item in items:
if type(item) == str:
self.include(item)
else:
item.write(self)
def writeln(self,s=""):
#print " "*self.__indent+s
self.file.write(" "*self.__indent+s+os.linesep)
class Vector:
def __init__(self,*args):
if len(args) == 1:
self.v = args[0]
else:
self.v = args
def __str__(self):
return "<%s>"%(", ".join([str(x)for x in self.v]))
def __repr__(self):
return "Vector(%s)"%self.v
def __mul__(self,other):
return Vector( [r*other for r in self.v] )
def __rmul__(self,other):
return Vector( [r*other for r in self.v] )
class Item:
def __init__(self,name,args=[],opts=[],**kwargs):
self.name = name
args=list(args)
for i in range(len(args)):
if type(args[i]) == tuple or type(args[i]) == list:
args[i] = Vector(args[i])
self.args = args
self.opts = opts
self.kwargs=kwargs
def append(self, item):
self.opts.append( item )
def write(self, file):
file.writeln( self.name )
file.block_begin()
if self.args:
file.writeln( ", ".join([str(arg) for arg in self.args]) )
for opt in self.opts:
if hasattr(opt,"write"):
opt.write(file)
else:
file.writeln( str(opt) )
for key,val in self.kwargs.items():
if type(val)==tuple or type(val)==list:
val = Vector(*val)
file.writeln( "%s %s"%(key,val) )
else:
file.writeln( "%s %s"%(key,val) )
file.block_end()
def __setattr__(self,name,val):
self.__dict__[name]=val
if name not in ["kwargs","args","opts","name"]:
self.__dict__["kwargs"][name]=val
def __setitem__(self,i,val):
if i < len(self.args):
self.args[i] = val
else:
i += len(args)
if i < len(self.opts):
self.opts[i] = val
def __getitem__(self,i,val):
if i < len(self.args):
return self.args[i]
else:
i += len(args)
if i < len(self.opts):
return self.opts[i]
class Texture(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"texture",(),opts,**kwargs)
class Pigment(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"pigment",(),opts,**kwargs)
class Finish(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"finish",(),opts,**kwargs)
class Normal(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"normal",(),opts,**kwargs)
class Camera(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"camera",(),opts,**kwargs)
class LightSource(Item):
def __init__(self,v,*opts,**kwargs):
Item.__init__(self,"light_source",(Vector(v),),opts,**kwargs)
class Background(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"background",(),opts,**kwargs)
class Box(Item):
def __init__(self,v1,v2,*opts,**kwargs):
#self.v1 = Vector(v1)
#self.v2 = Vector(v2)
Item.__init__(self,"box",(v1,v2),opts,**kwargs)
class Cylinder(Item):
def __init__(self,v1,v2,r,*opts,**kwargs):
" opts: open "
Item.__init__(self,"cylinder",(v1,v2,r),opts,**kwargs)
class Plane(Item):
def __init__(self,v,r,*opts,**kwargs):
Item.__init__(self,"plane",(v,r),opts,**kwargs)
class Torus(Item):
def __init__(self,r1,r2,*opts,**kwargs):
Item.__init__(self,"torus",(r1,r2),opts,**kwargs)
class Cone(Item):
def __init__(self,v1,r1,v2,r2,*opts,**kwargs):
" opts: open "
Item.__init__(self,"cone", (v1,r1,v2,r2),opts,**kwargs)
class Sphere(Item):
def __init__(self,v,r,*opts,**kwargs):
Item.__init__(self,"sphere",(v,r),opts,**kwargs)
class Union(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"union",(),opts,**kwargs)
class Intersection(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"intersection",(),opts,**kwargs)
class Difference(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"difference",(),opts,**kwargs)
class Merge(Item):
def __init__(self,*opts,**kwargs):
Item.__init__(self,"merge",(),opts,**kwargs)
x = Vector(1,0,0)
y = Vector(0,1,0)
z = Vector(0,0,1)
white = Texture(Pigment(color=(1,1,1)))
def tutorial31():
" from the povray tutorial sec. 3.1"
file=File("demo.pov","colors.inc","stones.inc")
cam = Camera(location=(0,2,-3),look_at=(0,1,2))
sphere = Sphere( (0,1,2), 2, Texture(Pigment(color="Yellow")))
light = LightSource( (2,4,-3), color="White")
file.write( cam, sphere, light )
def spiral():
" Fibonacci spiral "
gamma = (sqrt(5)-1)/2
file = File()
Camera(location=(0,0,-128), look_at=(0,0,0)).write(file)
LightSource((100,100,-100), color=(1,1,1)).write(file)
LightSource((150,150,-100), color=(0,0,0.3)).write(file)
LightSource((-150,150,-100), color=(0,0.3,0)).write(file)
LightSource((150,-150,-100), color=(0.3,0,0)).write(file)
theta = 0.0
for i in range(200):
r = i * 0.5
color = 1,1,1
v = [ r*sin(theta), r*cos(theta), 0 ]
Sphere( v, 0.7*sqrt(i),
Texture(
Finish(
ambient = 0.0,
diffuse = 0.0,
reflection = 0.85,
specular = 1
),
Pigment(color=color))
).write(file)
theta += gamma * 2 * pi
|
Why go out on a limb to use povray's SDL language when you can raytrace from the comfort of your favorite python chair?
This framework uses all of python's cool OO setattr, getattr, args, and *kwargs groovyness to create an extra lightweight fitting over povray's SDL files.
It means you can go absolutely bananas turning whatever complex mathematical/algorithmic structures you can comprehend (or not) into squeeky clean visuals and animations.
This is also an interesting exercise in structured text file generation; the author was influenced by Guido's bgen modules.
errata. Whoops; you will need this to run the fibonacci example:
Change it you can. You can submit a modified version of the recipe. Just find the recipe in "My Recipies" and click "Edit". It's handy when you goof up and, say, make a UI that puts quotation marks around everything (That would be me).
next release? Do you have plans for the next release? It's quite impressive with what you have here. It might be worth to make it a full-fledge version, to support all SDL features at version 3.5. For instance, adds 'global_settings', 'isosurface' etc. I'm very interested to know if you have plan or time on further works.
Overkill. This is a truly interesting project. But maybe to large for a python cookbook snippet, when you implement all that functionality.
Just what I was looking for! Thanks so much for this excellent code. Nothing to install, no versions to maintain, just PovRay objects in python. Excellent!
How to choose the size of the generated png file. Hello, Your script is saving my day, but I would like to generate e.g. 1024x1024 pixel png files. How can I change the default (320X240 on my machine) size? Many thanks
Lorenzo
This is really cool once you get the hang of it.
I added an Object class and blogged about it:
http://pyright.blogspot.com/2010/12/more-pov-ray.html