import turtle import math from math import sin, tan wn = turtle.Screen() wn.tracer(0) t = turtle.Turtle() t.setundobuffer(0) turtle.setworldcoordinates(-1,-1,1,1) vertices = [[-1, -1, -1], [-1, +1, -1], [+1, +1, -1], [+1, -1, -1], [-1, -1, +1], [+1, -1, +1], [+1, +1, +1], [-1, +1, +1], [-1, -1, -1], [-1, -1, +1], [-1, +1, +1], [-1, +1, -1], [+1, -1, -1], [+1, +1, -1], [+1, +1, +1], [+1, -1, +1], [+1, +1, -1], [-1, +1, -1], [-1, +1, +1], [+1, +1, +1], [+1, -1, -1], [+1, -1, +1], [-1, -1, +1], [-1, -1, -1]] def ident3(): return [[1,0,0],[0,1,0],[0,0,1]] def ident4(): return [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]] def dot(v1, v2): return sum(ea*eb for ea,eb in zip(v1,v2)) def transpose(m): return list(zip(*m)) def multvm(v, m): return [dot(v,b) for b in transpose(m)] def multmv(m, v): return [dot(v,b) for b in m] def multmm(m1, m2): return [multvm(a, m2) for a in m1] def translate4(v): Mt = ident4() Mt[0][3] = v[0] Mt[1][3] = v[1] Mt[2][3] = v[2] return Mt def multcm(c, m): return [[c*e for e in v] for v in m] def summm(m1, m2): return [[a+b for a,b in zip(v1,v2)] for v1,v2 in zip(m1,m2)] def diffv(v1, v2): return [a-b for a,b in zip(v1,v2)] def normal(triangle): v = diffv([triangle[3*2],triangle[3*2+1],triangle[3*2+2]],[triangle[0],triangle[1],triangle[2]]) w = diffv([triangle[3*3],triangle[3*3+1],triangle[3*3+2]],[triangle[0],triangle[1],triangle[2]]) nx = v[1]*w[2]-v[2]*w[1] ny = v[2]*w[0]-v[0]*w[2] nz = v[0]*w[1]-v[1]*w[0] return [nx,ny,nz] def magnitude(v): return math.sqrt(sum([x*x for x in v])) def rotate4(v, theta): mag = magnitude(v) x = v[0]/mag y = v[1]/mag z = v[2]/mag W = [[0,-z,y],[z,0,-x],[-y,x,0]] Mr = summm(ident3(),summm(multcm(sin(theta),W),multcm(2*sin(theta/2)*sin(theta/2), multmm(W,W)))) return [Mr[0]+[0],Mr[1]+[0],Mr[2]+[0],[0,0,0,1]] def rad(deg): return deg * math.pi / 180 def perspective(fov, aspect, near, far): tfov = tan(fov/2) Mp = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]] Mp[0][0] = 1/(aspect*tfov) Mp[1][1] = 1/tfov Mp[2][2] = -(far+near)/(far-near) Mp[2][3] = -1 Mp[3][2] = -(2*far*near)/(far-near) return Mp angle = 0 while True: t.clear() angle += 0.1 model = ident4() model = multmm(rotate4([0,0,1],rad(angle)),model) model = multmm(rotate4([1,1,0],rad(angle)),model) view = multmm(translate4([0,0,-5]),model) projection = perspective(rad(80), 1, 0.1, 100) T = multmm(projection, multmm(view, model)) transformed_vertices = [] for v in vertices: transformed_vector = multmv(T,v+[1]) transformed_vertices.append(transformed_vector) polygons = [] hidden = [] for i in range(len(transformed_vertices)//4): face = [] polygon = [] for j in range(0, 4): x,y,z,w = transformed_vertices[i*4+j] face+=[x,y,z] polygon+=[x/z,y/z] norm = normal(face) vec = [face[0],face[1],face[2]] if dot(norm, vec) > 0: hidden.append(False) else: hidden.append(True) polygons.append(polygon) # print(polygons) def poly(coords): t.up() t.teleport(coords[0], coords[1]) t.begin_fill() t.down() for i in range(2, len(coords), 2): t.goto(coords[i], coords[i + 1]) t.goto(coords[0], coords[1]) t.up() t.end_fill() for i in range(len(polygons)): if i % 6 == 0: t.fillcolor('red') elif i % 6 == 1: t.fillcolor('green') elif i % 6 == 2: t.fillcolor('yellow') elif i % 6 == 3: t.fillcolor('blue') elif i % 6 == 4: t.fillcolor('cyan') elif i % 6 == 5: t.fillcolor('magenta') if not hidden[i]: poly(polygons[i]) wn.update() wn.mainloop()