2.1 --- a/examples/PyGmy/ppygmy_points.py Sun Sep 16 00:02:49 2007 +0000
2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2.3 @@ -1,395 +0,0 @@
2.4 -#!/usr/bin/env python
2.5 -
2.6 -"""
2.7 -An adaptation of pygmy.py ("a rubbish raytracer") employing pprocess
2.8 -functionality in order to take advantage of multiprocessing environments.
2.9 -
2.10 ---------
2.11 -
2.12 -Copyright (C) 2005 Dave Griffiths
2.13 -Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
2.14 -
2.15 -This program is free software; you can redistribute it and/or
2.16 -modify it under the terms of the GNU General Public License
2.17 -as published by the Free Software Foundation; either version 2
2.18 -of the License, or (at your option) any later version.
2.19 -
2.20 -This program is distributed in the hope that it will be useful,
2.21 -but WITHOUT ANY WARRANTY; without even the implied warranty of
2.22 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.23 -GNU General Public License for more details.
2.24 -
2.25 -You should have received a copy of the GNU General Public License
2.26 -along with this program; if not, write to the Free Software
2.27 -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2.28 -"""
2.29 -
2.30 -import Image, ImageDraw, random, copy
2.31 -from math import *
2.32 -import pprocess
2.33 -import sys
2.34 -
2.35 -def sq(a):
2.36 - return a*a
2.37 -
2.38 -class vec:
2.39 - def __init__(self, x, y, z):
2.40 - self.x=float(x)
2.41 - self.y=float(y)
2.42 - self.z=float(z)
2.43 -
2.44 - def __add__(self,other):
2.45 - return vec(self.x+other.x,self.y+other.y,self.z+other.z)
2.46 -
2.47 - def __sub__(self,other):
2.48 - return vec(self.x-other.x,self.y-other.y,self.z-other.z)
2.49 -
2.50 - def __mul__(self,amount):
2.51 - return vec(self.x*amount,self.y*amount,self.z*amount)
2.52 -
2.53 - def __div__(self,amount):
2.54 - return vec(self.x/amount,self.y/amount,self.z/amount)
2.55 -
2.56 - def __neg__(self):
2.57 - return vec(-self.x,-self.y,-self.z)
2.58 -
2.59 - def dot(self,other):
2.60 - return (self.x*other.x)+(self.y*other.y)+(self.z*other.z)
2.61 -
2.62 - def cross(self,other):
2.63 - return vec(self.y*other.z - self.z*other.y,
2.64 - self.z*other.x - self.x*other.z,
2.65 - self.x*other.y - self.y*other.x)
2.66 -
2.67 - def dist(self,other):
2.68 - return sqrt((other.x-self.x)*(other.x-self.x)+
2.69 - (other.y-self.y)*(other.y-self.y)+
2.70 - (other.z-self.z)*(other.z-self.z))
2.71 -
2.72 - def sq(self):
2.73 - return sq(self.x)+sq(self.y)+sq(self.z)
2.74 -
2.75 - def mag(self):
2.76 - return self.dist(vec(0,0,0))
2.77 -
2.78 - def norm(self):
2.79 - mag=self.mag()
2.80 - if mag!=0:
2.81 - self.x=self.x/mag
2.82 - self.y=self.y/mag
2.83 - self.z=self.z/mag
2.84 -
2.85 - def reflect(self,normal):
2.86 - vdn=self.dot(normal)*2
2.87 - return self-normal*vdn
2.88 -
2.89 -class line:
2.90 - def __init__(self, start, end):
2.91 - self.start=start
2.92 - self.end=end
2.93 -
2.94 - def vec(self):
2.95 - return self.end-self.start
2.96 -
2.97 - def closestpoint(self, point):
2.98 - l=self.end-self.start
2.99 - l2=point-self.start
2.100 - t=l.dot(l2)
2.101 - if t<=0: return self.start
2.102 - if t>l.mag(): return self.end
2.103 - return self.start+l*t
2.104 -
2.105 -class renderobject:
2.106 - def __init__(self, shader):
2.107 - self.shader=shader
2.108 -
2.109 - def intersect(self,l):
2.110 - return "none",vec(0,0,0),vec(0,0,0) # type, position, normal
2.111 -
2.112 -class plane(renderobject):
2.113 - def __init__(self,plane,dist,shader):
2.114 - renderobject.__init__(self,shader)
2.115 - self.plane=plane
2.116 - self.dist=dist
2.117 -
2.118 - def intersect(self,l):
2.119 - vd=self.plane.dot(l.vec())
2.120 - if vd==0: return "none",vec(0,0,0),vec(0,0,0)
2.121 - v0 = -(self.plane.dot(l.start)+self.dist)
2.122 - t = v0/vd
2.123 - if t<0 or t>1: return "none",vec(0,0,0),vec(0,0,0)
2.124 - return "one",l.start+(l.vec()*t),self.plane
2.125 -
2.126 -
2.127 -class sphere(renderobject):
2.128 - def __init__(self, pos, radius, shader):
2.129 - renderobject.__init__(self,shader)
2.130 - self.pos=pos
2.131 - self.radius=radius
2.132 -
2.133 - def disttoline(self,l):
2.134 - return self.pos.dist(l.closestpoint(self.pos))
2.135 -
2.136 - def intersect(self,l):
2.137 - lvec=l.vec()
2.138 - a = sq(lvec.x)+sq(lvec.y)+sq(lvec.z)
2.139 -
2.140 - b = 2*(lvec.x*(l.start.x-self.pos.x)+ \
2.141 - lvec.y*(l.start.y-self.pos.y)+ \
2.142 - lvec.z*(l.start.z-self.pos.z))
2.143 -
2.144 - c = self.pos.sq()+l.start.sq() - \
2.145 - 2*(self.pos.x*l.start.x+self.pos.y*l.start.y+self.pos.z*l.start.z)-sq(self.radius)
2.146 -
2.147 - i = b*b-4*a*c
2.148 -
2.149 - intersectiontype="none"
2.150 - pos=vec(0,0,0)
2.151 - norm=vec(0,0,0)
2.152 - t=0
2.153 -
2.154 - if i>0 :
2.155 - if i==0:
2.156 - intersectiontype="one"
2.157 - t = -b/(2*a);
2.158 - else:
2.159 - intersectiontype="two"
2.160 - t = (-b - sqrt( b*b - 4*a*c )) / (2*a)
2.161 - # just bother with one for the moment
2.162 - # t2= (-b + sqrt( b*b - 4*a*c )) / (2*a)
2.163 -
2.164 - if t>0 and t<1:
2.165 - pos = l.start+lvec*t
2.166 - norm=pos-self.pos
2.167 - norm.norm()
2.168 - else:
2.169 - intersectiontype="none"
2.170 -
2.171 - return intersectiontype,pos,norm
2.172 -
2.173 - def intersects(self,l):
2.174 - return self.disttoline(l)<self.radius
2.175 -
2.176 -class light:
2.177 - def __init__(self):
2.178 - pass
2.179 -
2.180 - def checkshadow(self, obj, objects,l):
2.181 - # shadowing built into the lights (is this right?)
2.182 - for ob in objects:
2.183 - if ob is not obj:
2.184 - intersects,pos,norm = ob.intersect(l)
2.185 - if intersects is not "none":
2.186 - return 1
2.187 - return 0
2.188 -
2.189 - def light(self, obj, objects, pos, normal):
2.190 - pass
2.191 -
2.192 -class parallellight(light):
2.193 - def __init__(self, direction, col):
2.194 - direction.norm()
2.195 - self.direction=direction
2.196 - self.col=col
2.197 -
2.198 - def inshadow(self, obj, objects, pos):
2.199 - # create a longish line towards the light
2.200 - l = line(pos,pos+self.direction*1000)
2.201 - return self.checkshadow(obj,objects,l)
2.202 -
2.203 - def light(self, shaderinfo):
2.204 - if self.inshadow(shaderinfo["thisobj"],shaderinfo["objects"],shaderinfo["position"]): return vec(0,0,0)
2.205 - return self.col*self.direction.dot(shaderinfo["normal"])
2.206 -
2.207 -class pointlight(light):
2.208 - def __init__(self, position, col):
2.209 - self.position=position
2.210 - self.col=col
2.211 -
2.212 - def inshadow(self, obj, objects, pos):
2.213 - l = line(pos,self.position)
2.214 - return self.checkshadow(obj,objects,l)
2.215 -
2.216 - def light(self, shaderinfo):
2.217 - if self.inshadow(shaderinfo["thisobj"],shaderinfo["objects"],shaderinfo["position"]): return vec(0,0,0)
2.218 - direction = shaderinfo["position"]-self.position;
2.219 - direction.norm()
2.220 - direction=-direction
2.221 - return self.col*direction.dot(shaderinfo["normal"])
2.222 -
2.223 -class shader:
2.224 - def __init__(self):
2.225 - pass
2.226 -
2.227 - # a load of helper functions for shaders, need much improvement
2.228 -
2.229 - def getreflected(self,shaderinfo):
2.230 - depth=shaderinfo["depth"]
2.231 - col=vec(0,0,0)
2.232 - if depth>0:
2.233 - lray=copy.copy(shaderinfo["ray"])
2.234 - ray=lray.vec()
2.235 - normal=copy.copy(shaderinfo["normal"])
2.236 - ray=ray.reflect(normal)
2.237 - reflected=line(shaderinfo["position"],shaderinfo["position"]+ray)
2.238 - obj=shaderinfo["thisobj"]
2.239 - objects=shaderinfo["objects"]
2.240 - newshaderinfo = copy.copy(shaderinfo)
2.241 - newshaderinfo["ray"]=reflected
2.242 - newshaderinfo["depth"]=depth-1
2.243 - # todo - depth test
2.244 - for ob in objects:
2.245 - if ob is not obj:
2.246 - intersects,position,normal = ob.intersect(reflected)
2.247 - if intersects is not "none":
2.248 - newshaderinfo["thisobj"]=ob
2.249 - newshaderinfo["position"]=position
2.250 - newshaderinfo["normal"]=normal
2.251 - col=col+ob.shader.shade(newshaderinfo)
2.252 - return col
2.253 -
2.254 - def isoccluded(self,ray,shaderinfo):
2.255 - dist=ray.mag()
2.256 - test=line(shaderinfo["position"],shaderinfo["position"]+ray)
2.257 - obj=shaderinfo["thisobj"]
2.258 - objects=shaderinfo["objects"]
2.259 - # todo - depth test
2.260 - for ob in objects:
2.261 - if ob is not obj:
2.262 - intersects,position,normal = ob.intersect(test)
2.263 - if intersects is not "none":
2.264 - return 1
2.265 - return 0
2.266 -
2.267 - def doocclusion(self,samples,shaderinfo):
2.268 - # not really very scientific, or good in any way...
2.269 - oc=0.0
2.270 - for i in range(0,samples):
2.271 - ray=vec(random.randrange(-100,100),random.randrange(-100,100),random.randrange(-100,100))
2.272 - ray.norm()
2.273 - ray=ray*2.5
2.274 - if self.isoccluded(ray,shaderinfo):
2.275 - oc=oc+1
2.276 - oc=oc/float(samples)
2.277 - return 1-oc
2.278 -
2.279 - def getcolour(self,ray,shaderinfo):
2.280 - depth=shaderinfo["depth"]
2.281 - col=vec(0,0,0)
2.282 - if depth>0:
2.283 - test=line(shaderinfo["position"],shaderinfo["position"]+ray)
2.284 - obj=shaderinfo["thisobj"]
2.285 - objects=shaderinfo["objects"]
2.286 - newshaderinfo = copy.copy(shaderinfo)
2.287 - newshaderinfo["ray"]=test
2.288 - newshaderinfo["depth"]=depth-1
2.289 - # todo - depth test
2.290 - for ob in objects:
2.291 - if ob is not obj:
2.292 - intersects,position,normal = ob.intersect(test)
2.293 - if intersects is not "none":
2.294 - newshaderinfo["thisobj"]=ob
2.295 - newshaderinfo["position"]=position
2.296 - newshaderinfo["normal"]=normal
2.297 - col=col+ob.shader.shade(newshaderinfo)
2.298 - return col
2.299 -
2.300 - def docolourbleed(self,samples,shaderinfo):
2.301 - # not really very scientific, or good in any way...
2.302 - col=vec(0,0,0)
2.303 - for i in range(0,samples):
2.304 - ray=vec(random.randrange(-100,100),random.randrange(-100,100),random.randrange(-100,100))
2.305 - ray.norm()
2.306 - ray=ray*5
2.307 - col=col+self.getcolour(ray,shaderinfo)
2.308 - col=col/float(samples)
2.309 - return col
2.310 -
2.311 - def shade(self,shaderinfo):
2.312 - col=vec(0,0,0)
2.313 - for lite in shaderinfo["lights"]:
2.314 - col=col+lite.light(shaderinfo)
2.315 - return col
2.316 -
2.317 -class world:
2.318 - def __init__(self,width,height):
2.319 - self.lights=[]
2.320 - self.objects=[]
2.321 - self.cameratype="persp"
2.322 - self.width=width
2.323 - self.height=height
2.324 - self.backplane=2000.0
2.325 - self.imageplane=5.0
2.326 - self.aspect=self.width/float(self.height)
2.327 -
2.328 - def render_point(self, channel, sx, sy):
2.329 -
2.330 - """
2.331 - Render the given point, using the 'channel' provided to communicate
2.332 - result data back to the coordinating process, and using 'sx' and 'sy' as
2.333 - the point position. A tuple containing 'sx', 'sy' and a result is
2.334 - returned by this function via the given 'channel'.
2.335 - """
2.336 -
2.337 - x=2*(0.5-sx/float(self.width))*self.aspect
2.338 - y=2*(0.5-sy/float(self.height))
2.339 - if self.cameratype=="ortho":
2.340 - ray = line(vec(x,y,0),vec(x,y,self.backplane))
2.341 - else:
2.342 - ray = line(vec(0,0,0),vec(x,y,self.imageplane))
2.343 - ray.end=ray.end*self.backplane
2.344 -
2.345 - col=vec(0,0,0)
2.346 - depth=self.backplane
2.347 - shaderinfo={"ray":ray,"lights":self.lights,"objects":self.objects,"depth":2}
2.348 -
2.349 - for obj in self.objects:
2.350 - intersects,position,normal = obj.intersect(ray)
2.351 - if intersects is not "none":
2.352 - if position.z<depth and position.z>0:
2.353 - depth=position.z
2.354 - shaderinfo["thisobj"]=obj
2.355 - shaderinfo["position"]=position
2.356 - shaderinfo["normal"]=normal
2.357 - col=obj.shader.shade(shaderinfo)
2.358 -
2.359 - channel.send((sx, sy, col))
2.360 -
2.361 - def render(self, filename, limit):
2.362 -
2.363 - """
2.364 - Render the image with many processes, saving it to 'filename', using the
2.365 - given process 'limit' to constrain the number of processes used.
2.366 - """
2.367 -
2.368 - image = Image.new("RGB", (self.width,self.height))
2.369 - exchange = PyGmyExchange(limit=limit)
2.370 - exchange.draw = ImageDraw.Draw(image)
2.371 - exchange.total = self.width*self.height
2.372 - exchange.count = 0
2.373 -
2.374 - for y in range(0, self.height):
2.375 - for x in range(0,self.width):
2.376 - channel = pprocess.start(self.render_point, x, y)
2.377 - exchange.add_wait(channel)
2.378 -
2.379 - exchange.finish()
2.380 - image.save(filename)
2.381 -
2.382 -class PyGmyExchange(pprocess.Exchange):
2.383 -
2.384 - "A convenience class for parallelisation."
2.385 -
2.386 - def store_data(self, channel):
2.387 -
2.388 - "Store the data arriving on the given 'channel'."
2.389 -
2.390 - sx, sy, col = channel.receive()
2.391 - self.draw.point((sx,sy),fill=(col.x*255,col.y*255,col.z*255))
2.392 - self.count = self.count + 1
2.393 -
2.394 - percent = int((self.count/float(self.total))*100)
2.395 - sys.stdout.write(("\010" * 13) + "%3d%% %3d %3d" % (percent, sx, sy))
2.396 - sys.stdout.flush()
2.397 -
2.398 -# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/examples/PyGmy/scene_pmap.py Sun Sep 16 00:10:27 2007 +0000
4.3 @@ -0,0 +1,66 @@
4.4 +#!/usr/bin/env python
4.5 +
4.6 +"""
4.7 +An example scene from...
4.8 +
4.9 +http://www.pawfal.org/index.php?page=PyGmy
4.10 +"""
4.11 +
4.12 +import math
4.13 +from ppygmy_pmap import *
4.14 +import sys
4.15 +
4.16 +class everythingshader(shader):
4.17 + def __init__(self):
4.18 + pass
4.19 +
4.20 + def shade(self,shaderinfo):
4.21 + col = shader.shade(self,shaderinfo)
4.22 + ref = self.getreflected(shaderinfo)
4.23 + col = col*0.5+ref*0.5
4.24 + return col*self.doocclusion(10,shaderinfo)
4.25 +
4.26 +class spotshader(shader):
4.27 + def __init__(self):
4.28 + pass
4.29 +
4.30 + def shade(self,shaderinfo):
4.31 + col = shader.shade(self,shaderinfo)
4.32 + position=shaderinfo["position"]
4.33 + jitter=(math.sin(position.x)+math.cos(position.z))
4.34 + if jitter>0.5: col=col/2
4.35 + ref = self.getreflected(shaderinfo)
4.36 + return ref*0.5+col*0.5*self.doocclusion(10,shaderinfo)
4.37 +
4.38 +if __name__ == "__main__":
4.39 + w = world(300,200)
4.40 + numballs=10.0
4.41 + offset = vec(0,-5,55)
4.42 + rad=12.0
4.43 + radperball=(2*3.141)/numballs
4.44 +
4.45 + for i in range(0,int(numballs)):
4.46 + x=sin(0.3+radperball*float(i))*rad
4.47 + y=cos(0.3+radperball*float(i))*rad
4.48 + w.objects.append(sphere(vec(x,0,y)+offset,2,everythingshader()))
4.49 +
4.50 + w.objects.append(sphere(vec(3,3,0)+offset,5,everythingshader()))
4.51 + w.objects.append(plane(vec(0,1,0),7,spotshader()))
4.52 + w.lights.append(parallellight(vec(1,1,-1),vec(0.3,0.9,0.1)))
4.53 + w.lights.append(pointlight(vec(5,100,-5),vec(0.5,0.5,1)))
4.54 +
4.55 + if len(sys.argv) > 1:
4.56 + if "--help" in sys.argv:
4.57 + print "Specify a limit to the number of processes."
4.58 + print "For example:"
4.59 + print "python", sys.argv[0], "4"
4.60 + sys.exit(1)
4.61 + else:
4.62 + limit = int(sys.argv[1])
4.63 + else:
4.64 + limit = 1
4.65 +
4.66 + print "Number of processes:", limit
4.67 + w.render("test.tif", limit)
4.68 +
4.69 +# vim: tabstop=4 expandtab shiftwidth=4
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/examples/PyGmy/scene_queue.py Sun Sep 16 00:10:27 2007 +0000
5.3 @@ -0,0 +1,66 @@
5.4 +#!/usr/bin/env python
5.5 +
5.6 +"""
5.7 +An example scene from...
5.8 +
5.9 +http://www.pawfal.org/index.php?page=PyGmy
5.10 +"""
5.11 +
5.12 +import math
5.13 +from ppygmy_queue import *
5.14 +import sys
5.15 +
5.16 +class everythingshader(shader):
5.17 + def __init__(self):
5.18 + pass
5.19 +
5.20 + def shade(self,shaderinfo):
5.21 + col = shader.shade(self,shaderinfo)
5.22 + ref = self.getreflected(shaderinfo)
5.23 + col = col*0.5+ref*0.5
5.24 + return col*self.doocclusion(10,shaderinfo)
5.25 +
5.26 +class spotshader(shader):
5.27 + def __init__(self):
5.28 + pass
5.29 +
5.30 + def shade(self,shaderinfo):
5.31 + col = shader.shade(self,shaderinfo)
5.32 + position=shaderinfo["position"]
5.33 + jitter=(math.sin(position.x)+math.cos(position.z))
5.34 + if jitter>0.5: col=col/2
5.35 + ref = self.getreflected(shaderinfo)
5.36 + return ref*0.5+col*0.5*self.doocclusion(10,shaderinfo)
5.37 +
5.38 +if __name__ == "__main__":
5.39 + w = world(300,200)
5.40 + numballs=10.0
5.41 + offset = vec(0,-5,55)
5.42 + rad=12.0
5.43 + radperball=(2*3.141)/numballs
5.44 +
5.45 + for i in range(0,int(numballs)):
5.46 + x=sin(0.3+radperball*float(i))*rad
5.47 + y=cos(0.3+radperball*float(i))*rad
5.48 + w.objects.append(sphere(vec(x,0,y)+offset,2,everythingshader()))
5.49 +
5.50 + w.objects.append(sphere(vec(3,3,0)+offset,5,everythingshader()))
5.51 + w.objects.append(plane(vec(0,1,0),7,spotshader()))
5.52 + w.lights.append(parallellight(vec(1,1,-1),vec(0.3,0.9,0.1)))
5.53 + w.lights.append(pointlight(vec(5,100,-5),vec(0.5,0.5,1)))
5.54 +
5.55 + if len(sys.argv) > 1:
5.56 + if "--help" in sys.argv:
5.57 + print "Specify a limit to the number of processes."
5.58 + print "For example:"
5.59 + print "python", sys.argv[0], "4"
5.60 + sys.exit(1)
5.61 + else:
5.62 + limit = int(sys.argv[1])
5.63 + else:
5.64 + limit = 1
5.65 +
5.66 + print "Number of processes:", limit
5.67 + w.render("test.tif", limit)
5.68 +
5.69 +# vim: tabstop=4 expandtab shiftwidth=4