basic 3d raytracing
from math import * from kandinsky import * from time import monotonic,sleep class Vec: def __init__(self,a,b=None,c=None): if type(a)==Vec:self.x=a.x;self.y=a.y;self.z=a.z else:self.x=a;self.y=b;self.z=c def __add__(self,other): if type(other)in(int,float):other=Vec(other,other,other) return Vec(self.x+other.x,self.y+other.y,self.z+other.z) def __sub__(self,other): if type(other)in(int,float):other=Vec(other,other,other) return Vec(self.x-other.x,self.y-other.y,self.z-other.z) def __mul__(self,other): if type(other)in(int,float):other=Vec(other,other,other) return Vec(self.x*other.x,self.y*other.y,self.z*other.z) def __truediv__(self,other): if type(other)in(int,float):other=Vec(other,other,other) return Vec(self.x/other.x,self.y/other.y,self.z/other.z) def distanceTo(self,other):return (self-Vec(other)).magnitude() def magnitude(self):return sqrt(self.x**2+self.y**2+self.z**2) def normalize(self):return self.__truediv__(self.magnitude()) def unit(self):return self.normalize() def __index__(self,other): if type(other)!=int:raise TypeError('Vector indices must be integers, not '.format(other)) if other not in range(0,2):raise IndexError('Vector index out of range, expected a value in range(0,2)') return[self.x,self.y,self.z][other] def __iter__(self): for i in (self.x,self.y,self.z):yield i class Color: def __init__(self,a,b=None,c=None,d=1): if type(a)==Color:self.r=a.r;self.g=a.g;self.b=a.b;self.a=a.a if type(a)==type(b)==type(c)==int and(type(d)==float or type(d)==int):self.r=a;self.g=b;self.b=c;self.a=d if type(a)==int and type(b)==type(c)==None:self.r=(a&4278190080)>>24;self.b=(a&16711680)>>16;self.g=(a&65280)>>8;self.a=(a&255)>>0 def __add__(self,other): if type(other)in(float,int):other=Color(other,other,other,1) return Color(max(0,min(255,floor(self.r+other.r*other.a))),max(0,min(255,floor(self.g+other.g*other.a))),max(0,min(255,floor(self.b+other.b*other.a))),max(0,min(self.a+other.a,1))) def __sub__(self,other): if type(other)in(float,int):other=Color(other,other,other,1) return Color(max(0,min(255,floor(self.r-other.r*other.a))),max(0,min(255,floor(self.g-other.g*other.a))),max(0,min(255,floor(self.b-other.b*other.a))),max(0,min(self.a+other.a,1))) def __mul__(self,other): if type(other)in(float,int):other=Color(other,other,other,1) return Color(max(0,min(255,floor(self.r*(other.r*other.a)))),max(0,min(255,floor(self.g*(other.g*other.a)))),max(0,min(255,floor(self.b*(other.b*other.a)))),max(0,min(self.a+other.a,1))) def __truediv__(self,other): if type(other)in(float,int):other=Color(other,other,other,1) return Color(max(0,min(255,floor(self.r/(other.r*other.a)))),max(0,min(255,floor(self.g/(other.g*other.a)))),max(0,min(255,floor(self.b/(other.b*other.a)))),max(0,min(self.a+other.a,1))) def __int__(self):return self.r<<16&self.g<<8&self.b def __index__(self,other): if type(other)!=int:raise TypeError('Color indices must be integers, not '.format(other)) if other not in range(0,2):raise IndexError('Color index out of range, expected a value in range(0,2)') return[self.r,self.g,self.b][other] def __iter__(self): for i in (self.r,self.g,self.b):yield i class Shape: def __init__(self,*a,**kwa):... def intersects(self,p):... def color(self):... class Sphere(Shape): def __init__(self,pos,radius,color):self.colorValue=Color(color);self.pos=Vec(pos);self.radius=radius def intersects(self,p):return (self.pos-p).magnitude()<self.radius def color(self):return self.colorValue camerapos=Vec(0,0,0) camerasize=5 cameralength=2 resolution=100,100 precision=1 maxrange=10 shapes=[Sphere(Vec(0,0,2),1,Color(255,0,0))] enable_shadows=False enable_reflections=True max_reflections=1 lightpos=Vec(0,5,3) voidColor=Color(0,0,60) def calculateColor(source,direction,bouncesLeft): ray=Vec(source);i=0 while i<precision*maxrange: ray=ray.__add__(direction.__truediv__(precision)) for obj in shapes: if obj.intersects(ray): hit=False;color=Color(obj.color()) if enable_shadows: ld=lightpos.__sub__(ray).unit();rr=Vec(ray);rr+=ld/precision while 1: rr+=ld/precision if lightpos.distanceTo(rr)<1/precision*1.5:break dd=False for objj in shapes: if objj.intersects(rr):hit=True;dd=True if dd:break if hit:color=Color(color)/4 return Color(color) i=i+1 return voidColor s=floor(240/resolution[1]) for px in range(0,resolution[0]): for py in range(0,resolution[1]):direction=Vec(camerasize/2-px/resolution[0]*camerasize,camerasize/2-py/resolution[1]*camerasize,cameralength).unit();ray=Vec(camerapos);c=calculateColor(ray,direction,max_reflections);fill_rect(px*s,py*s,s,s,tuple(c)) input()