Guest User

tiny tracer no vector class

a guest
Jan 9th, 2013
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.29 KB | None | 0 0
  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. from math import sqrt, pow, pi
  7. import Image, sys
  8.  
  9. def vMul(a,b):  return [ a[0]*b[0], a[1]*b[1], a[2]*b[2] ]
  10. def vMulD(a,b): return [ a[0]*b,    a[1]*b,    a[2]*b    ]
  11. def vAdd(a,b):  return [ a[0]+b[0], a[1]+b[1], a[2]+b[2] ]
  12. def vAddD(a,b): return [ a[0]+b,    a[1]+b,    a[2]+b    ]
  13. def vSub(a,b):  return [ a[0]-b[0], a[1]-b[1], a[2]-b[2] ]
  14. def vSubD(a,b): return [ a[0]-b,    a[1]-b,    a[2]-b    ]
  15. def vNeg(a):    return [-a[0],     -a[1],     -a[2]      ]
  16. def vPow(a,b):  return [ a[0]**b,   a[1]**b,   a[2]**b   ]
  17.  
  18. def vDot(a,b):  return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
  19. def vSqr(a):    return vDot(a,a)
  20. def vLen(a):    return sqrt(vSqr(a))
  21. def vNorm(a):   return vMulD(a, 1.0/vLen(a))
  22.  
  23. class Sphere( object ):
  24.    
  25.     def __init__(self, center, radius, color):
  26.         self.c = center
  27.         self.r = radius
  28.         self.col = color
  29.        
  30.     def intersection(self, l):
  31.         q = vDot(l.d, vSub(l.o, self.c))**2 - vSqr(vSub(l.o, self.c)) + self.r**2
  32.         if q < 0:
  33.             return Intersection( [0,0,0], -1, [0,0,0], self)
  34.         else:
  35.             d = -vDot(l.d, vSub(l.o, self.c))
  36.             d1 = d - sqrt(q)
  37.             d2 = d + sqrt(q)
  38.             if 0 < d1 and ( d1 < d2 or d2 < 0):
  39.                 return Intersection(vAdd(l.o,vMulD(l.d,d1)), d1, self.normal(vAdd(l.o,vMulD(l.d,d1))), self)
  40.             elif 0 < d2 and ( d2 < d1 or d1 < 0):
  41.                 return Intersection(vAdd(l.o,vMulD(l.d,d2)), d2, self.normal(vAdd(l.o,vMulD(l.d,d2))), self)
  42.             else:
  43.                 return Intersection( [0,0,0], -1, [0,0,0], self)
  44.    
  45.     def normal(self, b):
  46.         return vNorm(vSub(b,self.c))
  47.    
  48. class Plane( object ):
  49.    
  50.     def __init__(self, point, normal, color):
  51.         self.n = normal
  52.         self.p = point
  53.         self.col = color
  54.        
  55.     def intersection(self, l):
  56.         d = vDot(l.d, self.n)
  57.         if d == 0:
  58.             return Intersection( [0,0,0], -1, vector[0,0,0], self)
  59.         else:
  60.             d = vDot(vSub(self.p,l.o),self.n) / d
  61.             return Intersection(vAdd(l.o,vMulD(l.d,d)), d, self.n, self)
  62.    
  63. class Ray( object ):
  64.    
  65.     def __init__(self, origin, direction):
  66.         self.o = origin
  67.         self.d = direction
  68.        
  69. class Intersection( object ):
  70.    
  71.     def __init__(self, point, distance, normal, obj):
  72.         self.p = point
  73.         self.d = distance
  74.         self.n = normal
  75.         self.obj = obj
  76.        
  77. def testRay(ray, objects, ignore=None):
  78.     intersect = Intersection( [0,0,0], -1, [0,0,0], None)
  79.    
  80.     for obj in objects:
  81.         if obj is not ignore:
  82.             currentIntersect = obj.intersection(ray)
  83.             if currentIntersect.d > 0 and intersect.d < 0:
  84.                 intersect = currentIntersect
  85.             elif 0 < currentIntersect.d < intersect.d:
  86.                 intersect = currentIntersect
  87.     return intersect
  88.    
  89. def trace(ray, objects, light, maxRecur):
  90.     if maxRecur < 0:
  91.         return [0,0,0]
  92.     intersect = testRay(ray, objects)
  93.     if intersect.d == -1:
  94.         col = [AMBIENT,AMBIENT,AMBIENT]
  95.     elif vDot(intersect.n, vSub(light,intersect.p)) < 0:
  96.         col = vMulD(intersect.obj.col, AMBIENT)
  97.     else:
  98.         lightRay = Ray(intersect.p, vNorm(vSub(light,intersect.p)))
  99.         if testRay(lightRay, objects, intersect.obj).d == -1:
  100.             lightIntensity = 1000.0/(4*pi*vLen(vSub(light,intersect.p))**2)
  101.             col = vMulD(intersect.obj.col, max(vDot(vNorm(intersect.n),vMulD(vNorm(vSub(light,intersect.p)),lightIntensity)), AMBIENT))
  102.         else:
  103.             col = vMulD(intersect.obj.col, AMBIENT)
  104.     return col
  105.    
  106. def gammaCorrection(color,factor):
  107.     return (int(pow(color[0]/255.0,factor)*255),
  108.             int(pow(color[1]/255.0,factor)*255),
  109.             int(pow(color[2]/255.0,factor)*255))
  110.  
  111. AMBIENT = 0.1
  112. GAMMA_CORRECTION = 1/2.2
  113. MAX_RECURSION = 10
  114.  
  115. #these are left global so we don't have to pass them to apply_async each pixel
  116. objs = [ Sphere([-2, 0,-10], 2,   [0,255,0]),
  117.          Sphere([ 2, 0,-10], 3.5, [255,0,0]),
  118.          Sphere([ 0,-4,-10], 3,   [0,0,255]),
  119.          Plane([0,0,-12], [0,0,1], [255,255,255]) ]
  120.  
  121. lightSource = [0,10,0]
  122. cameraPos = [0,0,20]
  123.  
  124. def main():
  125.     img = Image.new("RGB",(500,500))
  126.     for x in range(500):
  127.         results = []
  128.         for y in range(500):
  129.             ray =  Ray(cameraPos, vNorm(vSub([x/50.0-5, y/50.0-5, 0], cameraPos)))
  130.             col = trace(ray, objs, lightSource, MAX_RECURSION)
  131.             img.putpixel((x,499-y),gammaCorrection(col,GAMMA_CORRECTION))
  132.         print x
  133.         sys.stdout.flush()
  134.     img.save("trace.bmp","BMP")
  135.  
  136. if __name__ == '__main__':
  137.     main()
Add Comment
Please, Sign In to add comment