class Render(object): def __init__(self, width=None, height=None): self.x = 0 self.y = 0 self.view = {} self.color = color(255, 255, 255) if (width == None and height == None): self.bmp = None self.width = width self.height = height else: self.glCreateWindow(width, height) def glInit(self): pass def glCreateWindow(self, width, height): self.bmp = Bitmap(width, height) self.width = width self.height = height def glViewPort(self, x, y, width, height): self.view['x'] = x self.view['y'] = y self.view['width'] = width - 1 self.view['height'] = height - 1 def glClear(self): self.bmp.clear() def glClearColor(self, r, g, b): for i in range(self.height): for j in range(self.width): self.bmp.point( i, j, color(trunc(r * 255), trunc(g * 255), trunc(b * 255))) def glVertex(self, x, y): self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1)) self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1)) self.glVertexC(self.x, self.y) def glVertexC(self, x, y): self.bmp.point(y, x, self.color) def glColorC(self, r, g, b): self.color = color(r, g, b) def glColorFull(self, color): self.color = color def glColor(self, r, g, b): self.color = color(floor(r * 255), floor(g * 255), floor(b * 255)) def glFinish(self, name='out'): self.bmp.write(name + '.bmp') def glLine(self, x0p, y0p, x1p, y1p): x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1)) y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1)) x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1)) y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1)) self.glLineC(x0, y0, x1, y1) def glLineC(self, x0, y0, x1, y1): dx = abs(x1 - x0) dy = abs(y1 - y0) if x1 < x0: x0, x1 = x1, x0 y0, y1 = y1, y0 px = 2 * dy - dx py = 2 * dx - dy if dx >= dy: y = y0 for x in range(x0, x1 + 1): # print(x) # print(y) self.glVertexC(x, y) if px < 0: px += 2 * dy else: y += 1 if y0 < y1 else -1 px += 2 * (dy - dx) else: x = x0 step = 1 if y0 < y1 else -1 for y in range(y0, y1, step): # print(x) # print(y) self.glVertexC(x, y) if py < 0: py += 2 * dx else: x += 1 if x0 < x1 else -1 py += 2 * (dx - dy) def loadObj(self, filename, translateX=0, translateY=0, scale=1, texture=None, light=[0, 0, 1]): with open(filename) as file: faces, vertices, textures_coor = obj.processObj(file) # light = [0.3, 0.1, 0.6] # light = [0, 0, 1] for face in faces: #Se obtienen las coordenadas de los vertices faceLen = len(face) faceVer = [] faceTex = [] for i in range(faceLen): faceVer.append( transform_vertex(vertices[face[i][0] - 1], translateX=translateX, translateY=translateY, scale=scale)) faceTex.append(textures_coor[face[i][1] - 1]) #Se obtiene la intensidad dot = cross_product(vector_subs(faceVer[1], faceVer[0]), vector_subs(faceVer[2], faceVer[0])) norm = normalize(dot) light_int = dot_product(norm, light) #Se recorren todos los vertices de cada cara loopLen = faceLen - 2 for i in range(loopLen): if light_int > 0: if not texture: self.glColor(light_int, light_int, light_int) self.barycentric_triangle(faceVer[0], faceVer[i + 1], faceVer[i + 2], tex_coor=(faceTex[0], faceTex[i + 1], faceTex[i + 2]), texture=texture, intensity=light_int) def display(self, name='out'): self.glFinish(name) try: from wand.image import Image from wand.display import display with Image(filename=name + '.bmp') as image: display(image) except Exception as e: print(e) pass def barycentric_triangle(self, A, B, C, tex_coor=(), texture=None, intensity=1): x_min, x_max, y_min, y_max = bounding_box(A, B, C) for i in range(x_min, x_max + 1): for j in range(y_min, y_max + 1): u, v, w = barycentric2(A, B, C, [i, j]) if u >= 0 and v >= 0 and w >= 0: if texture: tex_A, tex_B, tex_C = tex_coor tex_x = tex_A[0] * u + tex_B[0] * v + tex_C[0] * w tex_y = tex_A[1] * u + tex_B[1] * v + tex_C[1] * w self.glColorFull( texture.getColor(tex_x, tex_y, intensity)) P_z = dot_product([u, v, w], [A[2], B[2], C[2]]) if self.bmp.getZbuffer(i, j) < P_z: self.bmp.setZbuffer(i, j, P_z) self.glVertexC(i, j)
class Render(object): def __init__(self, width=None, height=None): self.x = 0 self.y = 0 self.view = {} self.color = color(255, 255, 255) if (width == None and height == None): self.bmp = None self.width = width self.height = height else: self.glCreateWindow(width, height) def glInit(self): pass def glCreateWindow(self, width, height): self.bmp = Bitmap(width, height) self.width = width self.height = height def glViewPort(self, x, y, width, height): self.view['x'] = x self.view['y'] = y self.view['width'] = width - 1 self.view['height'] = height - 1 def glClear(self): self.bmp.clear() def glClearColor(self, r, g, b): for i in range(self.height): for j in range(self.width): self.bmp.point( i, j, color(trunc(r * 255), trunc(g * 255), trunc(b * 255))) def glVertex(self, x, y): self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1)) self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1)) self.glVertexC(self.x, self.y) def glVertexC(self, x, y): self.bmp.point(y, x, self.color) def glColorC(self, r, g, b): self.color = color(r, g, b) def glColorFull(self, color): self.color = color def glColor(self, r, g, b): self.color = color(floor(r * 255), floor(g * 255), floor(b * 255)) def glFinish(self, name='out'): self.bmp.write(name + '.bmp') def glLine(self, x0p, y0p, x1p, y1p): x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1)) y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1)) x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1)) y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1)) self.glLineC(x0, y0, x1, y1) def glLineC(self, x0, y0, x1, y1): dx = abs(x1 - x0) dy = abs(y1 - y0) if x1 < x0: x0, x1 = x1, x0 y0, y1 = y1, y0 px = 2 * dy - dx py = 2 * dx - dy if dx >= dy: y = y0 for x in range(x0, x1 + 1): # print(x) # print(y) self.glVertexC(x, y) if px < 0: px += 2 * dy else: y += 1 if y0 < y1 else -1 px += 2 * (dy - dx) else: x = x0 step = 1 if y0 < y1 else -1 for y in range(y0, y1, step): # print(x) # print(y) self.glVertexC(x, y) if py < 0: py += 2 * dx else: x += 1 if x0 < x1 else -1 py += 2 * (dx - dy) def loadObj(self, filename, translate=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0], texture=None, light=[0, 0, 1]): with open(filename) as file: faces, vertices, textures_coor = obj.processObj(file) self.calcModelMat(rotate, scale, translate) for i in range(len(vertices)): vertices[i] = self.transform(vertices[i]) # light = [0.3, 0.1, 0.6] # light = [0, 0, 1] asdf = 0 for face in faces: asdf += 1 print(asdf) #Se obtienen las coordenadas de los vertices faceLen = len(face) faceVer = [] faceTex = [] for i in range(faceLen): faceVer.append(vertices[face[i][0] - 1]) # faceVer.append(transform_vertex( # vertices[face[i][0] - 1], # translateX=translateX, # translateY=translateY, # scale=scale # )) if texture: faceTex.append(textures_coor[face[i][1] - 1]) #Se obtiene la intensidad dot = cross_product(vector_subs(faceVer[1], faceVer[0]), vector_subs(faceVer[2], faceVer[0])) norm = normalize(dot) light_int = dot_product(norm, light) #Se recorren todos los vertices de cada cara loopLen = faceLen - 2 if faceLen <= 4: for i in range(loopLen): if light_int > 0: if not texture: self.glColor(light_int, light_int, light_int) tex_coor_temp = None else: tex_coor_temp = (faceTex[0], faceTex[i + 1], faceTex[i + 2]) self.barycentric_triangle(faceVer[0], faceVer[i + 1], faceVer[i + 2], tex_coor=tex_coor_temp, texture=texture, intensity=light_int) def calcViewportMat(self, x=0, y=0): res = [[self.width / 2, 0, 0, x + self.width / 2], [0, self.height / 2, 0, y + self.height / 2], [0, 0, 100, 100], [0, 0, 0, 1]] self.viewport_matrix = res def calcModelMat(self, rotate=[0, 0, 0], scale=[1, 1, 1], translate=[0, 0, 0]): rotate_x = [[1, 0, 0, 0], [0, cos(rotate[0]), -sin(rotate[0]), 0], [0, sin(rotate[0]), cos(rotate[0]), 0], [0, 0, 0, 1]] rotate_y = [[cos(rotate[1]), 0, sin(rotate[1]), 0], [0, 1, 0, 0], [-sin(rotate[1]), 0, cos(rotate[1]), 0], [0, 0, 0, 1]] rotate_z = [[cos(rotate[2]), -sin(rotate[2]), 0, 0], [sin(rotate[2]), cos(rotate[2]), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] rotate_all = matmul(matmul(rotate_x, rotate_y), rotate_z) translation = [[1, 0, 0, translate[0]], [0, 1, 0, translate[1]], [0, 0, 1, translate[2]], [0, 0, 0, 1]] scale_mat = [[scale[0], 0, 0, 0], [0, scale[1], 0, 0], [0, 0, scale[2], 0], [0, 0, 0, 1]] self.model_matrix = matmul(matmul(translation, rotate_all), scale_mat) def calcViewMat(self, x, y, z, center): view_mat = [[x[0], x[1], x[2], -center[0]], [y[0], y[1], y[2], -center[1]], [z[0], z[1], z[2], -center[2]], [0, 0, 0, 1]] self.view_matrix = view_mat def calcProjectionMat(self, c): proj = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, c, 1]] self.proj_matrix = proj def transform(self, vertex): vertex = [[vertex[0]], [vertex[1]], [vertex[2]], [1]] homog_mat = matmul( matmul( matmul(matmul(self.viewport_matrix, self.proj_matrix), self.view_matrix), self.model_matrix), vertex) trans_vertex = [ round(homog_mat[0][0] / homog_mat[3][0]), round(homog_mat[1][0] / homog_mat[3][0]), round(homog_mat[2][0] / homog_mat[3][0]) ] return trans_vertex def lookAt(self, cameraPos, cameraTarget, up): z = normalize(vector_subs(cameraPos, cameraTarget)) x = normalize(cross_product(up, z)) y = normalize(cross_product(z, x)) self.calcViewMat(x, y, z, cameraTarget) self.calcProjectionMat( -1 / vec_length(vector_subs(cameraPos, cameraTarget))) self.calcViewportMat() def barycentric_triangle(self, A, B, C, tex_coor=(), texture=None, intensity=1): x_min, x_max, y_min, y_max = bounding_box(A, B, C) for i in range(x_min, x_max + 1): for j in range(y_min, y_max + 1): if i < 0 or j < 0: continue u, v, w = barycentric2(A, B, C, [i, j]) if u >= 0 and v >= 0 and w >= 0: if texture: tex_A, tex_B, tex_C = tex_coor tex_x = tex_A[0] * u + tex_B[0] * v + tex_C[0] * w tex_y = tex_A[1] * u + tex_B[1] * v + tex_C[1] * w self.glColorFull( texture.getColor(tex_x, tex_y, intensity)) P_z = dot_product([u, v, w], [A[2], B[2], C[2]]) if j < len(self.bmp.zbuffer) and i < len( self.bmp.zbuffer[j]) and self.bmp.getZbuffer( i, j) < P_z: self.bmp.setZbuffer(i, j, P_z) self.glVertexC(i, j)
class Render(object): def __init__(self, width = None, height = None): self.x = 0 self.y = 0 self.view = {} self.color = color(255, 255, 255) if (width == None and height == None): self.bmp = None self.width = width self.height = height else: self.glCreateWindow(width, height) def glInit(self): pass def glCreateWindow(self, width, height): self.bmp = Bitmap(width, height) self.width = width self.height = height def glViewPort(self, x, y, width, height): self.view['x'] = x self.view['y'] = y self.view['width'] = width - 1 self.view['height'] = height - 1 def glClear(self): self.bmp.clear() def glClearColor(self, r, g, b): for i in range(self.height): for j in range(self.width): self.bmp.point(i, j, color(trunc(r * 255), trunc(g * 255), trunc(b * 255))) def glVertex(self, x, y): self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1)) self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1)) self.glVertexC(self.x, self.y) def glVertexC(self, x, y): self.bmp.point(y, x, self.color) def glColor(self, r, g, b): self.color = color(floor(r * 255), floor(g * 255), floor(b * 255)) def glFinish(self, name = 'out'): self.bmp.write(name+'.bmp') def glLine(self, x0p, y0p, x1p, y1p): x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1)) y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1)) x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1)) y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1)) self.glLineC(x0, y0, x1, y1) def glLineC(self, x0, y0, x1, y1): dx = abs(x1 - x0) dy = abs(y1 - y0) if x1 < x0: x0, x1 = x1, x0 y0, y1 = y1, y0 px = 2 * dy - dx py = 2 * dx - dy if dx >= dy: y = y0 for x in range(x0, x1 + 1): # print(x) # print(y) self.glVertexC(x, y) if px < 0: px += 2 * dy else: y += 1 if y0 < y1 else -1 px += 2 * (dy - dx) else: x = x0 step = 1 if y0 < y1 else -1 for y in range(y0, y1, step): # print(x) # print(y) self.glVertexC(x, y) if py < 0: py += 2 * dx else: x += 1 if x0 < x1 else -1 py += 2 * (dx - dy) def loadObj(self, filename, translateX=0, translateY=0, scale=1, triangle=0): with open(filename) as file: faces, vertices = obj.processObj(file) light = [0.2, 0.3, 0.5] for face in faces: faceLen = len(face) faceVer = [] for i in range(faceLen): faceVer.append(transform_vertex( vertices[face[i][0] - 1], translateX=translateX, translateY=translateY, scale=scale )) loopLen = faceLen - 2 for i in range(loopLen): dot = cross_product(vector_subs(faceVer[i+1], faceVer[0]), vector_subs(faceVer[i+2], faceVer[0])) norm = normalize(dot) light_int = dot_product(norm, light) if light_int > 0: self.glColor(light_int, light_int, light_int) self.barycentric_triangle(faceVer[0], faceVer[i+1], faceVer[i+2]) def display(self, name = 'out'): self.glFinish(name) try: from wand.image import Image from wand.display import display with Image(filename = name + '.bmp') as image: display(image) except Exception as e: print(e) pass # do nothing if no wand is installed # def line_sweeping_triangle(self, A, B, C): # if (A[1] > B[1]): # A, B = B, A # if (B[1] > C[1]): # B, C = C, B # if (A[1] > B[1]): # A, B = B, A # # self.glLineC(A[0], A[1], B[0], B[1]) # self.glLineC(A[0], A[1], C[0], C[1]) # self.glLineC(B[0], B[1], C[0], C[1]) # # for i in range(A[1], B[1]): # x0 = round(x(A, C, i)) # x1 = round(x(A, B, i)) # self.glLineC(x0, i, x1, i) # # for i in range(B[1], C[1]): # x0 = round(x(A, C, i)) # x1 = round(x(B, C, i)) # self.glLineC(x0, i, x1, i) def barycentric_triangle(self, A, B, C): x_min, x_max, y_min, y_max = bounding_box(A, B, C) for i in range(x_min, x_max + 1): for j in range(y_min, y_max + 1): u, v, w = barycentric2(A, B, C, [i, j]) if u >= 0 and v >= 0 and w >= 0: P_z = dot_product([u, v, w], [A[2], B[2], C[2]]) if self.bmp.getZbuffer(i, j) < P_z: self.bmp.setZbuffer(i, j, P_z) self.glVertexC(i, j)