Permalink
Browse files

Display the picture live in a Tkinter window.

  • Loading branch information...
1 parent 200da20 commit 30138d3ecdadafdbbf5482c9fab170980c798567 @jedie committed Nov 24, 2011
Showing with 111 additions and 78 deletions.
  1. +111 −78 CodeSnippets/PyRayTracer/raytrace.py
@@ -15,6 +15,7 @@
print 'Not using psyco.'
import math
+import Tkinter as tkinter
EPSILON = 0.00001
@@ -79,15 +80,15 @@ def mustBePoint(self):
def reflectThrough(self, normal):
d = normal.scale(self.dot(normal))
- return self - d.scale(2)
+ return self -d.scale(2)
-Vector.ZERO = Vector(0,0,0)
-Vector.RIGHT = Vector(1,0,0)
-Vector.UP = Vector(0,1,0)
-Vector.OUT = Vector(0,0,1)
+Vector.ZERO = Vector(0, 0, 0)
+Vector.RIGHT = Vector(1, 0, 0)
+Vector.UP = Vector(0, 1, 0)
+Vector.OUT = Vector(0, 0, 1)
assert Vector.RIGHT.reflectThrough(Vector.UP) == Vector.RIGHT
-assert Vector(-1,-1,0).reflectThrough(Vector.UP) == Vector(-1,1,0)
+assert Vector(-1, -1, 0).reflectThrough(Vector.UP) == Vector(-1, 1, 0)
class Point:
def __init__(self, initx, inity, initz):
@@ -135,7 +136,7 @@ def __repr__(self):
def intersectionTime(self, ray):
cp = self.centre - ray.point
v = cp.dot(ray.vector)
- discriminant = (self.radius * self.radius) - (cp.dot(cp) - v*v)
+ discriminant = (self.radius * self.radius) - (cp.dot(cp) - v * v)
if discriminant < 0:
return None
else:
@@ -173,10 +174,10 @@ def __repr__(self):
def pointAtTime(self, t):
return self.point + self.vector.scale(t)
-Point.ZERO = Point(0,0,0)
+Point.ZERO = Point(0, 0, 0)
-a = Vector(3,4,12)
-b = Vector(1,1,1)
+a = Vector(3, 4, 12)
+b = Vector(1, 1, 1)
class PpmCanvas:
def __init__(self, width, height, filenameBase):
@@ -191,14 +192,39 @@ def __init__(self, width, height, filenameBase):
def plot(self, x, y, r, g, b):
i = ((self.height - y - 1) * self.width + x) * 3
self.bytes[i ] = max(0, min(255, int(r * 255)))
- self.bytes[i+1] = max(0, min(255, int(g * 255)))
- self.bytes[i+2] = max(0, min(255, int(b * 255)))
+ self.bytes[i + 1] = max(0, min(255, int(g * 255)))
+ self.bytes[i + 2] = max(0, min(255, int(b * 255)))
def save(self):
with open(self.filenameBase + '.ppm', 'wb') as f:
f.write('P6 %d %d 255\n' % (self.width, self.height))
f.write(self.bytes.tostring())
+class TkCanvas(object):
+ def __init__(self, width, height):
+ self.width = width
+ self.height = height
+
+ self.root = tkinter.Tk()
+ self.image = tkinter.PhotoImage(width=self.width, height=self.height)
+ lb1 = tkinter.Label(self.root, image=self.image)
+ lb1.pack()
+
+ self.root.update()
+
+ def plot(self, x, y, r, g, b):
+ r = max(0, min(255, int(r * 255)))
+ g = max(0, min(255, int(g * 255)))
+ b = max(0, min(255, int(b * 255)))
+
+ y = self.height - y
+
+ self.image.put("#%02x%02x%02x" % (r, g, b), (x, y))
+
+ def save(self):
+ self.root.update()
+
+
def firstIntersection(intersections):
result = None
for i in intersections:
@@ -208,6 +234,63 @@ def firstIntersection(intersections):
result = i
return result
+def addColours(a, scale, b):
+ return (a[0] + scale * b[0],
+ a[1] + scale * b[1],
+ a[2] + scale * b[2])
+
+class SimpleSurface:
+ def __init__(self, **kwargs):
+ self.baseColour = kwargs.get('baseColour', (1, 1, 1))
+ self.specularCoefficient = kwargs.get('specularCoefficient', 0.2)
+ self.lambertCoefficient = kwargs.get('lambertCoefficient', 0.6)
+ self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient
+
+ def baseColourAt(self, p):
+ return self.baseColour
+
+ def colourAt(self, scene, ray, p, normal):
+ b = self.baseColourAt(p)
+
+ c = (0, 0, 0)
+ if self.specularCoefficient > 0:
+ reflectedRay = Ray(p, ray.vector.reflectThrough(normal))
+ #print p, normal, ray.vector, reflectedRay.vector
+ reflectedColour = scene.rayColour(reflectedRay)
+ c = addColours(c, self.specularCoefficient, reflectedColour)
+
+ if self.lambertCoefficient > 0:
+ lambertAmount = 0
+ for lightPoint in scene.visibleLights(p):
+ contribution = (lightPoint - p).normalized().dot(normal)
+ if contribution > 0:
+ lambertAmount = lambertAmount + contribution
+ lambertAmount = min(1, lambertAmount)
+ c = addColours(c, self.lambertCoefficient * lambertAmount, b)
+
+ if self.ambientCoefficient > 0:
+ c = addColours(c, self.ambientCoefficient, b)
+
+ return c
+
+class CheckerboardSurface(SimpleSurface):
+ def __init__(self, **kwargs):
+ SimpleSurface.__init__(self, **kwargs)
+ self.otherColour = kwargs.get('otherColour', (0, 0, 0))
+ self.checkSize = kwargs.get('checkSize', 1)
+
+ def baseColourAt(self, p):
+ v = p - Point.ZERO
+ v.scale(1.0 / self.checkSize)
+ if (int(abs(v.x) + 0.5) + \
+ int(abs(v.y) + 0.5) + \
+ int(abs(v.z) + 0.5)) \
+ % 2:
+ return self.otherColour
+ else:
+ return self.baseColour
+
+
class Scene:
def __init__(self):
self.objects = []
@@ -245,30 +328,30 @@ def render(self, canvas):
print 'Looping over pixels'
previousfraction = 0
- for y in range(canvas.height):
+ for y in xrange(canvas.height):
currentfraction = float(y) / canvas.height
if currentfraction - previousfraction > 0.05:
canvas.save()
print '%d%% complete' % (currentfraction * 100)
previousfraction = currentfraction
- for x in range(canvas.width):
+ for x in xrange(canvas.width):
xcomp = vpRight.scale(x * pixelWidth - halfWidth)
ycomp = vpUp.scale(y * pixelHeight - halfHeight)
ray = Ray(eye.point, eye.vector + xcomp + ycomp)
colour = self.rayColour(ray)
- canvas.plot(x,y,*colour)
+ canvas.plot(x, y, *colour)
print 'Complete.'
def rayColour(self, ray):
if self.recursionDepth > 3:
- return (0,0,0)
+ return (0, 0, 0)
try:
self.recursionDepth = self.recursionDepth + 1
intersections = [(o, o.intersectionTime(ray), s) for (o, s) in self.objects]
i = firstIntersection(intersections)
if i is None:
- return (0,0,0) ## the background colour
+ return (0, 0, 0) ## the background colour
else:
(o, t, s) = i
p = ray.pointAtTime(t)
@@ -278,7 +361,7 @@ def rayColour(self, ray):
def _lightIsVisible(self, l, p):
for (o, s) in self.objects:
- t = o.intersectionTime(Ray(p,l - p))
+ t = o.intersectionTime(Ray(p, l - p))
if t is not None and t > EPSILON:
return False
return True
@@ -290,74 +373,24 @@ def visibleLights(self, p):
result.append(l)
return result
-def addColours(a, scale, b):
- return (a[0] + scale * b[0],
- a[1] + scale * b[1],
- a[2] + scale * b[2])
-
-class SimpleSurface:
- def __init__(self, **kwargs):
- self.baseColour = kwargs.get('baseColour', (1,1,1))
- self.specularCoefficient = kwargs.get('specularCoefficient', 0.2)
- self.lambertCoefficient = kwargs.get('lambertCoefficient', 0.6)
- self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient
-
- def baseColourAt(self, p):
- return self.baseColour
-
- def colourAt(self, scene, ray, p, normal):
- b = self.baseColourAt(p)
-
- c = (0,0,0)
- if self.specularCoefficient > 0:
- reflectedRay = Ray(p, ray.vector.reflectThrough(normal))
- #print p, normal, ray.vector, reflectedRay.vector
- reflectedColour = scene.rayColour(reflectedRay)
- c = addColours(c, self.specularCoefficient, reflectedColour)
-
- if self.lambertCoefficient > 0:
- lambertAmount = 0
- for lightPoint in scene.visibleLights(p):
- contribution = (lightPoint - p).normalized().dot(normal)
- if contribution > 0:
- lambertAmount = lambertAmount + contribution
- lambertAmount = min(1,lambertAmount)
- c = addColours(c, self.lambertCoefficient * lambertAmount, b)
- if self.ambientCoefficient > 0:
- c = addColours(c, self.ambientCoefficient, b)
-
- return c
-
-class CheckerboardSurface(SimpleSurface):
- def __init__(self, **kwargs):
- SimpleSurface.__init__(self, **kwargs)
- self.otherColour = kwargs.get('otherColour', (0,0,0))
- self.checkSize = kwargs.get('checkSize', 1)
+if __name__ == '__main__':
+ #Canvas = PpmCanvas
+ Canvas = TkCanvas
- def baseColourAt(self, p):
- v = p - Point.ZERO
- v.scale(1.0 / self.checkSize)
- if (int(abs(v.x) + 0.5) + \
- int(abs(v.y) + 0.5) + \
- int(abs(v.z) + 0.5)) \
- % 2:
- return self.otherColour
- else:
- return self.baseColour
+ c = Canvas(320, 240)
+ #c = Canvas(640, 480, 'test_raytrace_big')
-if __name__ == '__main__':
- Canvas = PpmCanvas
- #c = Canvas(320,240,'test_raytrace')
- c = Canvas(640,480,'test_raytrace_big')
s = Scene()
s.addLight(Point(30, 30, 10))
s.addLight(Point(-10, 100, 30))
s.lookAt(Point(0, 3, 0))
- s.addObject(Sphere(Point(1,3,-10), 2), SimpleSurface(baseColour = (1,1,0)))
+ s.addObject(Sphere(Point(1, 3, -10), 2), SimpleSurface(baseColour=(1, 1, 0)))
for y in range(6):
s.addObject(Sphere(Point(-3 - y * 0.4, 2.3, -5), 0.4),
- SimpleSurface(baseColour = (y / 6.0, 1 - y / 6.0, 0.5)))
- s.addObject(Halfspace(Point(0,0,0), Vector.UP), CheckerboardSurface())
+ SimpleSurface(baseColour=(y / 6.0, 1 - y / 6.0, 0.5)))
+ s.addObject(Halfspace(Point(0, 0, 0), Vector.UP), CheckerboardSurface())
s.render(c)
c.save()
+
+ c.root.mainloop()

0 comments on commit 30138d3

Please sign in to comment.