def norm(v0): """ Input: 1 size 3 vector Output: Size 3 vector with the normal of the vector """ v0length = length(v0) if not v0length: return V3(0, 0, 0) return V3(v0.x / v0length, v0.y / v0length, v0.z / v0length)
def cross(v0, v1): """ Input: 2 size 3 vectors Output: Size 3 vector with the cross product """ return V3( v0.y * v1.z - v0.z * v1.y, v0.z * v1.x - v0.x * v1.z, v0.x * v1.y - v0.y * v1.x, )
def barycentric(A, B, C, P): """ Input: 3 size 2 vectors and a point Output: 3 barycentric coordinates of the point in relation to the triangle formed * returns -1, -1, -1 for degenerate triangles """ cx, cy, cz = cross(V3(B.x - A.x, C.x - A.x, A.x - P.x), V3(B.y - A.y, C.y - A.y, A.y - P.y)) if abs(cz) < 1: return -1, -1, -1 # this triangle is degenerate, return anything outside # [cx cy cz] = [u v 1] u = cx / cz v = cy / cz w = 1 - (u + v) return w, v, u
def load(self, filename, translate, scale): model = Obj(filename) light = V3(0, 0, 1) for face in model.faces: vcount = len(face) if vcount == 3: f1 = face[0][0] - 1 f2 = face[1][0] - 1 f3 = face[2][0] - 1 a = self.transform(model.vertices[f1], translate, scale) b = self.transform(model.vertices[f2], translate, scale) c = self.transform(model.vertices[f3], translate, scale) normal = norm(cross(sub(b, a), sub(c, a))) intensity = dot(normal, light) grey = round(255 * intensity) if grey < 0: continue self.triangle(a, b, c, intensity) else: # assuming 4 f1 = face[0][0] - 1 f2 = face[1][0] - 1 f3 = face[2][0] - 1 f4 = face[3][0] - 1 vertices = [ self.transform(model.vertices[f1], translate, scale), self.transform(model.vertices[f2], translate, scale), self.transform(model.vertices[f3], translate, scale), self.transform(model.vertices[f4], translate, scale) ] normal = norm( cross(sub(vertices[0], vertices[1]), sub(vertices[1], vertices[2]))) # no necesitamos dos normales!! intensity = dot(normal, light) grey = round(255 * intensity) if grey < 0: continue # dont paint this face # vertices are ordered, no need to sort! # vertices.sort(key=lambda v: v.x + v.y) A, B, C, D = vertices self.triangle(A, B, C, intensity) self.triangle(A, C, D, intensity)
def mul(v0, k): """ Input: 2 size 3 vectors Output: Size 3 vector with the per element multiplication """ return V3(v0.x * k, v0.y * k, v0.z * k)
def sub(v0, v1): """ Input: 2 size 3 vectors Output: Size 3 vector with the per element substraction """ return V3(v0.x - v1.x, v0.y - v1.y, v0.z - v1.z)
def transform(self, vertex, translate=(0, 0, 0), scale=(1, 1, 1)): # returns a vertex 3, translated and transformed return V3(round((vertex[0] + translate[0]) * scale[0]), round((vertex[1] + translate[1]) * scale[1]), round((vertex[2] + translate[2]) * scale[2]))
def sum(v0, v1): """ Input: 2 size 3 vectors Output: Size 3 vector with the per element sum """ return V3(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z)
def __init__(self): self.paintColor = WHITE self.bufferColor = BLACK self.light = V3(0, 0, 1)