Want more features on Pastebin? Sign Up, it's FREE!
Guest

Untitled

By: a guest on Jan 10th, 2013  |  syntax: Python  |  size: 5.61 KB  |  views: 45  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
This paste has a previous version, view the difference. Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #tiny-tracer-no-vector-class. 2x speedup.
  2.  
  3. #original pastebin: http://pastebin.com/F8f5GHJZ
  4. #original thread:   http://www.reddit.com/r/tinycode/comments/169ri9/ray_tracer_in_140_sloc_of_python_with_picture/
  5.  
  6. import timeit
  7.  
  8. from math import sqrt, pow, pi
  9. import Image, sys
  10.  
  11. def vMul(a,b):  return ( a[0]*b[0], a[1]*b[1], a[2]*b[2] )
  12. def vMulD(a,b): return ( a[0]*b,    a[1]*b,    a[2]*b    )
  13. def vAdd(a,b):  return ( a[0]+b[0], a[1]+b[1], a[2]+b[2] )
  14. def vAddD(a,b): return ( a[0]+b,    a[1]+b,    a[2]+b    )
  15. def vSub(a,b):  return ( a[0]-b[0], a[1]-b[1], a[2]-b[2] )
  16. def vSubD(a,b): return ( a[0]-b,    a[1]-b,    a[2]-b    )
  17. def vNeg(a):    return (-a[0],     -a[1],     -a[2]      )
  18. def vPow(a,b):  return ( a[0]**b,   a[1]**b,   a[2]**b   )
  19.  
  20. def vDot(a,b):  return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
  21. def vSqr(a):    return vDot(a,a)
  22. def vLen(a):    return sqrt(vSqr(a))
  23. def vNorm(a):   return vMulD(a, 1.0/vLen(a))
  24.  
  25. class Sphere( object ):
  26.        
  27.         def __init__(self, center, radius, color):
  28.                 self.c = center
  29.                 self.r = radius
  30.                 self.col = color
  31.                
  32.         def intersection(self, l):
  33.                 q = vDot(l.d, vSub(l.o, self.c))**2 - vSqr(vSub(l.o, self.c)) + self.r**2
  34.                 if q < 0:
  35.                         return Intersection( (0,0,0), -1, (0,0,0), self)
  36.                 else:
  37.                         d = -vDot(l.d, vSub(l.o, self.c))
  38.                         d1 = d - sqrt(q)
  39.                         d2 = d + sqrt(q)
  40.                         if 0 < d1 and ( d1 < d2 or d2 < 0):
  41.                                 return Intersection(vAdd(l.o,vMulD(l.d,d1)), d1, self.normal(vAdd(l.o,vMulD(l.d,d1))), self)
  42.                         elif 0 < d2 and ( d2 < d1 or d1 < 0):
  43.                                 return Intersection(vAdd(l.o,vMulD(l.d,d2)), d2, self.normal(vAdd(l.o,vMulD(l.d,d2))), self)
  44.                         else:
  45.                                 return Intersection( (0,0,0), -1, (0,0,0), self)
  46.        
  47.         def normal(self, b):
  48.                 return vNorm(vSub(b,self.c))
  49.        
  50. class Plane( object ):
  51.        
  52.         def __init__(self, point, normal, color):
  53.                 self.n = normal
  54.                 self.p = point
  55.                 self.col = color
  56.                
  57.         def intersection(self, l):
  58.                 d = vDot(l.d, self.n)
  59.                 if d == 0:
  60.                         return Intersection( (0,0,0), -1, vector(0,0,0), self)
  61.                 else:
  62.                         d = vDot(vSub(self.p,l.o),self.n) / d
  63.                         return Intersection(vAdd(l.o,vMulD(l.d,d)), d, self.n, self)
  64.        
  65. class Ray( object ):
  66.        
  67.         def __init__(self, origin, direction):
  68.                 self.o = origin
  69.                 self.d = direction
  70.                
  71. class Intersection( object ):
  72.        
  73.         def __init__(self, point, distance, normal, obj):
  74.                 self.p = point
  75.                 self.d = distance
  76.                 self.n = normal
  77.                 self.obj = obj
  78.                
  79. def testRay(ray, objects, ignore=None):
  80.         intersect = Intersection( (0,0,0), -1, (0,0,0), None)
  81.        
  82.         for obj in objects:
  83.                 if obj is not ignore:
  84.                         currentIntersect = obj.intersection(ray)
  85.                         if currentIntersect.d > 0 and intersect.d < 0:
  86.                                 intersect = currentIntersect
  87.                         elif 0 < currentIntersect.d < intersect.d:
  88.                                 intersect = currentIntersect
  89.         return intersect
  90.        
  91. def trace(ray, objects, light, maxRecur):
  92.         if maxRecur < 0:
  93.                 return (0,0,0)
  94.         intersect = testRay(ray, objects)
  95.         if intersect.d == -1:
  96.                 col = (AMBIENT,AMBIENT,AMBIENT)
  97.         elif vDot(intersect.n, vSub(light,intersect.p)) < 0:
  98.                 col = vMulD(intersect.obj.col, AMBIENT)
  99.         else:
  100.                 lightRay = Ray(intersect.p, vNorm(vSub(light,intersect.p)))
  101.                 if testRay(lightRay, objects, intersect.obj).d == -1:
  102.                         lightIntensity = 1000.0/(4*pi*vLen(vSub(light,intersect.p))**2)
  103.                         col = vMulD(intersect.obj.col, max(vDot(vNorm(intersect.n),vMulD(vNorm(vSub(light,intersect.p)),lightIntensity)), AMBIENT))
  104.                 else:
  105.                         col = vMulD(intersect.obj.col, AMBIENT)
  106.         return col
  107.        
  108. def gammaCorrection(color,factor):
  109.         return (int(pow(color[0]/255.0,factor)*255),
  110.                         int(pow(color[1]/255.0,factor)*255),
  111.                         int(pow(color[2]/255.0,factor)*255))
  112.  
  113. AMBIENT = 0.1
  114. GAMMA_CORRECTION = 1/2.2
  115. MAX_RECURSION = 10
  116.  
  117. #these are left global so we don't have to pass them to apply_async each pixel
  118. objs = ( Sphere((-2, 0,-10), 2,   (0,255,0)),
  119.          Sphere(( 2, 0,-10), 3.5, (255,0,0)),
  120.          Sphere(( 0,-4,-10), 3,   (0,0,255)),
  121.          Plane((0,0,-12), (0,0,1), (255,255,255)) )
  122.  
  123. lightSource = (0,10,0)
  124. cameraPos = (0,0,20)
  125.  
  126. def main():
  127.         img = Image.new("RGB",(500,500))
  128.         for x in range(500):
  129.                 results = []
  130.                 for y in range(500):
  131.                         ray =  Ray(cameraPos, vNorm(vSub((x/50.0-5, y/50.0-5, 0), cameraPos)))
  132.                         col = trace(ray, objs, lightSource, MAX_RECURSION)
  133.                         img.putpixel((x,499-y),gammaCorrection(col,GAMMA_CORRECTION))
  134.         img.save("trace.bmp","BMP")
  135.  
  136. if __name__ == '__main__':
  137.         timer = timeit.Timer(stmt='main()',setup="from __main__ import main")
  138.         t = timer.timeit(number=1)
  139.         print "t = %f"%t
clone this paste RAW Paste Data