def _build_polygon(self, radius, z, segments=32, reverse_vertex_order=False): """ Generate a polygon given number of segments and radius :param radius: :param z: :param segments: :param reverse_vertex_order: :return: """ vertex_start_index = len(self.vertices) for i in range(segments): angle = (math.pi / 2) + (i / segments) * 2 * math.pi x = radius * math.cos(angle) y = radius * math.sin(angle) vertex = Vector3(x, y, z) self.vertices.append(vertex) if i >= 2: if reverse_vertex_order: face = Face3(vertex_start_index + i, vertex_start_index + i-1, vertex_start_index) else: face = Face3(vertex_start_index, vertex_start_index + i - 1, vertex_start_index + i) normal = self.calculate_normal(face) face.vertex_normals = [normal, normal, normal] self.faces.append(face)
def _build_cylinder(self): """ Generate faces between top and bottom faces :return: """ top_circle_vertex_start_index = len(self.vertices) // 2 for i in range(top_circle_vertex_start_index): base_v0 = i base_v1 = i + 1 top_v0 = i + top_circle_vertex_start_index top_v1 = top_v0 + 1 if base_v1 == top_circle_vertex_start_index: base_v1 = 0 top_v1 = top_circle_vertex_start_index # two points on first circle, one on second circle face = Face3(base_v0, base_v1, top_v0) normal = self.calculate_normal(face) face.vertex_normals = [normal, normal, normal] self.faces.append(face) # one point on first circle, two on second circle face = Face3(base_v1, top_v1, top_v0) normal = self.calculate_normal(face) face.vertex_normals = [normal, normal, normal] self.faces.append(face)
def build_sphere(self, radius, sectors, stacks): for i in range(stacks): stack_angle = math.pi * ((1 / 2) - (i / stacks)) xy = radius * math.cos(stack_angle) z = radius * math.sin(stack_angle) # add(sectorCount + 1) vertices per stack # the first and last vertices have same position and normal, but different tex coords for j in range(sectors): sector_angle = j * 2 * math.pi / sectors # vertex position x y z x = xy * math.cos(sector_angle) y = xy * math.sin(sector_angle) vec = Vector3(x, y, z) self.vertices.append(vec) # normals # length_inv = 1 / radius # nx = x * length_inv # ny = y * length_inv # nz = z * length_inv # normal = Vector3(nx, ny, nz) # self.normals.append(normal) # tex coords (s, t) range between [0, 1] # TODO: https://www.songho.ca/opengl/gl_sphere.html for i in range(stacks): k_1 = i * (sectors) # beginning of current stack k_2 = k_1 + sectors # beginning of next stack for j in range(sectors): # faces # # if i = 0: # face = Face3(0, k_2) # if i != 0: face = Face3(k_1, k_2, k_1 + 1) # normal = self.calculate_normal(face) # face.vertex_normals = [normal, normal, normal] self.faces.append(face) if i != (stacks - 1): face = Face3(k_1 + 1, k_2, k_2 + 1) # normal = self.calculate_normal(face) # face.vertex_normals = [normal, normal, normal] self.faces.append(face) k_1 += 1 k_2 += 1 for face in self.faces: if face.a > len(self.vertices) \ or face.b > len(self.vertices) \ or face.c > len(self.vertices): print(face)
def create_mesh(self): """ Create real mesh object from the geometry and material """ max_faces = 65530//3 #geometries = [] start = 0 while(True): _faces=[] _vertices = [] if (len(self.stl_mesh.v0)-start) >= max_faces: print("Faces are more than max") length = max_faces # # mesh = STLMesh(self.stl_mesh.v0[start:start+length], self.stl_mesh.v1[start:start+length], self.stl_mesh.v2[start:start+length], self.stl_mesh.normals[start:start+length], # self.material) # # self.add(mesh) _vertices = np.concatenate((self.stl_mesh.v0[start:start+length],self.stl_mesh.v1[start:start+length],self.stl_mesh.v2[start:start+length])) for i in range(length): f3 = Face3(i,i+length, i+ length*2) f3.vertex_normals = [self.stl_mesh.normals[start+i],self.stl_mesh.normals[start+i],self.stl_mesh.normals[start+i]] _faces.append(f3) geo = Geometry() geo.vertices = _vertices geo.faces = _faces mesh = Mesh(geo, self.material) self.add(mesh) start = start+length else: length = len(self.stl_mesh.v0)-start _vertices = np.concatenate((self.stl_mesh.v0[start:],self.stl_mesh.v1[start:],self.stl_mesh.v2[start:])) for i in range(length): f3 = Face3(i,i+length, i+ length*2) f3.vertex_normals = [self.stl_mesh.normals[i+start],self.stl_mesh.normals[i+start],self.stl_mesh.normals[i+start]] _faces.append(f3) geo = Geometry() geo.vertices = _vertices geo.faces = _faces #geometries.append(geo) mesh = Mesh(geo, self.material) self.add(mesh) # length = max_faces # # mesh = STLMesh(self.stl_mesh.v0[start:], self.stl_mesh.v1[start:], self.stl_mesh.v2[start:], self.stl_mesh.normals[start:], # self.material) # # self.add(mesh) break return self
def _build_msh(self): for v in self.msh_vertices: v0 = Vector3(v[0] * 0.4, v[1] * 0.4, v[2] * 0.4) self.vertices.append((v0[0], v0[1], v0[2])) print len(self.vertices) n_idx = 0 for f in self.msh_faces: face3 = Face3(*f) normal = self.msh_normals[n_idx] #face3.vertex_normals = [normal, normal, normal] face3.normal = normal n_idx += 1 self.faces.append(face3)
def _build_box(self): for v in self._cube_vertices: v = Vector3(0.5 * v[0] * self.w, 0.5 * v[1] * self.h, 0.5 * v[2] * self.d) self.vertices.append(v) n_idx = 0 for f in self._cube_faces: face3 = Face3(*f) normal = self._cube_normals[floor(n_idx / 2)] face3.vertex_normals = [normal, normal, normal] n_idx += 1 self.faces.append(face3)
def _build_tri(self): for v in self._tri_vertices: v = Vector3(0.5 * v[0] * self.w, 0.5 * v[1] * self.h, 0.5 * v[2] * self.d) self.vertices.append(v) n_idx = 0 for f in self._tri_faces: face3 = Face3(*f) normal = self._tri_normals[n_idx / 2] face3.vertex_normals = [normal, normal, normal] n_idx += 1 self.faces.append(face3)
def _build_mesh(self, stl_mesh): for i in range(stl_mesh.attr.size): for j in range(3): v = Vector3(stl_mesh.vectors[i][j][0], stl_mesh.vectors[i][j][1], stl_mesh.vectors[i][j][2]) self.vertices.append(v) f_index = i * 3 face3 = Face3(f_index, f_index + 1, f_index + 2) face3.normal = Vector3(stl_mesh.normals[i][0], stl_mesh.normals[i][1], stl_mesh.normals[i][2]) face3.vertex_normals = [face3.normal, face3.normal, face3.normal] self.faces.append(face3)
def convert_to_mesh(self, vertex_format=None): """Converts data gotten from the .obj definition file and create Kivy3 Mesh object which may be used for drawing object in the scene """ geometry = Geometry() material = Material() mtl_dirname = os.path.abspath(os.path.dirname(self.loader.mtl_source)) v_idx = 0 # create geometry for mesh for f in self.faces: verts = f[0] norms = f[1] tcs = f[2] face3 = Face3(0, 0, 0) for i, e in enumerate(['a', 'b', 'c']): #get normal components n = (0.0, 0.0, 0.0) if norms[i] != -1: n = self.loader.normals[norms[i] - 1] face3.vertex_normals.append(n) #get vertex components v = self.loader.vertices[verts[i] - 1] geometry.vertices.append(v) setattr(face3, e, v_idx) v_idx += 1 #get texture coordinate components t = (0.0, 0.0) if tcs[i] != -1: t = self.loader.texcoords[tcs[i] - 1] tc = Vector2(t[0], 1. - t[1]) geometry.face_vertex_uvs[0].append(tc) geometry.faces.append(face3) # apply material for object if self.mtl_name in self.loader.mtl_contents: raw_material = self.loader.mtl_contents[self.mtl_name] for k, v in raw_material.iteritems(): _k = self._mtl_map.get(k, None) if k in [ "map_Kd", ]: map_path = os.path.join(mtl_dirname, v[0]) tex = Image(map_path).texture material.map = tex continue if _k: if len(v) == 1: v = float(v[0]) if k == 'Tr': v = 1. - v setattr(material, _k, v) else: v = map(lambda x: float(x), v) setattr(material, _k, v) mesh = Mesh(geometry, material) return mesh
def _build_cylinder(self): _cylinder_vertices = [] top_vertices = [] bottom_vertices = [] cylinder_side_normals = [] _cylinder_normals = [] for i in range(self.circle_segment): x = math.cos( float(i) * (2. * math.pi) / float(self.circle_segment)) * 0.5 * float(self.rad) y = math.sin( float(i) * (2. * math.pi) / float(self.circle_segment)) * 0.5 * float(self.rad) n = Vector3(x, y, 0) n.normalize() cylinder_side_normals.append(n) top_vertices.append((x, y, 0.5 * float(self.length))) bottom_vertices.append((x, y, -0.5 * float(self.length))) _cylinder_vertices = top_vertices + bottom_vertices _cylinder_normals = cylinder_side_normals + cylinder_side_normals for f in range(1, self.circle_segment - 1): # Top circle normal = Vector3(0, 0, 1) face = (0, f, f + 1) face3 = Face3(*face) face3.vertex_normals = [normal, normal, normal] self.faces.append(face3) for f in range(self.circle_segment + 1, (2 * self.circle_segment) - 1): # Top circle normal = Vector3(0, 0, -1) face = (self.circle_segment, f, f + 1) face3 = Face3(*face) face3.vertex_normals = [normal, normal, normal] self.faces.append(face3) for i in range(0, self.circle_segment): if i == (self.circle_segment - 1): face = (i, 0, i + self.circle_segment) else: face = (i, i + 1, i + self.circle_segment) face3 = Face3(*face) face3.vertex_normals = [ _cylinder_normals[i], _cylinder_normals[i + 1], _cylinder_normals[i + self.circle_segment] ] self.faces.append(face3) if i == (self.circle_segment - 1): face = (0, i + self.circle_segment, self.circle_segment) face3 = Face3(*face) face3.vertex_normals = (_cylinder_normals[i + 1], _cylinder_normals[i + self.circle_segment], _cylinder_normals[self.circle_segment]) else: face = (i + 1, i + self.circle_segment, i + self.circle_segment + 1) face3 = Face3(*face) face3.vertex_normals = (_cylinder_normals[i + 1], _cylinder_normals[i + self.circle_segment], _cylinder_normals[i + self.circle_segment + 1]) self.faces.append(face3) self.vertices = _cylinder_vertices
def _build_sphere(self): #Create Vertices and normals _vertices = [] _normals = [] #Top vertex _vertices.append((0, 0, 1. * self.rad)) _normals.append((0, 0, 1)) # Generate the faces for i in range(1, self.stacks): theta_1 = float(i) * (math.pi / self.stacks) z = math.cos(theta_1) for j in range(self.sectors): theta_2 = float(j) * (2. * math.pi / self.sectors) x = math.sin(theta_1) * math.cos(theta_2) y = math.sin(theta_1) * math.sin(theta_2) vertex = (x * self.rad, y * self.rad, z * self.rad) _vertices.append(vertex) _normals.append((x, y, z)) # Bottom vertex _vertices.append((0, 0, -1. * self.rad)) _normals.append((0, 0, -1.)) # Generate the Faces with mapping to the vertices #Top one for i in range(1, self.sectors + 1): a = 0 b = i c = i + 1 if c == self.sectors + 1: c = 1 face3 = Face3(a, b, c) face3.vertex_normals = [_normals[a], _normals[b], _normals[c]] self.faces.append(face3) #Stacks: for i in range(0, self.stacks - 2): top_idx = (i * self.sectors + 1, (i + 1) * self.sectors + 1) for j in range(top_idx[0], top_idx[1]): a = j b = j + 1 c = j + self.sectors if b == top_idx[1]: b = top_idx[0] face3 = Face3(a, b, c) face3.vertex_normals = [_normals[a], _normals[b], _normals[c]] self.faces.append(face3) a = j + 1 b = j + self.sectors c = j + self.sectors + 1 if a == top_idx[1]: a = top_idx[0] if c == top_idx[1] + self.sectors: c = top_idx[1] face3 = Face3(a, b, c) face3.vertex_normals = [_normals[a], _normals[b], _normals[c]] self.faces.append(face3) for i in range(len(_vertices) - 1 - self.sectors, len(_vertices) - 1): a = len(_vertices) - 1 b = i c = i + 1 if c == len(_vertices) - 1: c = len(_vertices) - 1 - self.sectors face3 = Face3(a, b, c) face3.vertex_normals = [_normals[a], _normals[b], _normals[c]] self.faces.append(face3) self.vertices = _vertices
def convert_to_mesh(self, vertex_format=None): """Converts data gotten from the .obj definition file and create Kivy3 Mesh object which may be used for drawing object in the scene """ geometry = Geometry() material = Material() mtl_dirname = abspath(dirname(self.loader.mtl_source)) v_idx = 0 # create geometry for mesh for f in self.faces: verts = f[0] norms = f[1] tcs = f[2] face3 = Face3(0, 0, 0) for i, e in enumerate(['a', 'b', 'c']): # get normal components n = (0.0, 0.0, 0.0) if norms[i] != -1: n = self.loader.normals[norms[i] - 1] face3.vertex_normals.append(n) # get vertex components v = self.loader.vertices[verts[i] - 1] geometry.vertices.append(v) setattr(face3, e, v_idx) v_idx += 1 # get texture coordinate components t = (0.0, 0.0) if tcs[i] != -1: t = self.loader.texcoords[tcs[i] - 1] tc = Vector2(t[0], 1. - t[1]) geometry.face_vertex_uvs[0].append(tc) geometry.faces.append(face3) # apply material for object if self.mtl_name in self.loader.mtl_contents: raw_material = self.loader.mtl_contents[self.mtl_name] # shader ignores values zeros = ['0', '0.0', '0.00', '0.000', '0.0000', '0.00000', '0.000000'] for k, v in raw_material.items(): _k = self._mtl_map.get(k, None) # TODO: also handle map_Ka and map_Ks if k in ["map_Kd", ]: # TODO: map file path may contains spaces. # current implementation fails. map_path = join(mtl_dirname, v[0]) if not exists(map_path): msg = u'WaveObject: Texture not found <{}>' Logger.warning(msg.format(map_path)) continue tex = Image(map_path).texture material.map = tex continue if _k: if len(v) == 1: v[0] = '0.000001' if v[0] in zeros else v[0] v = float(v[0]) if k == 'Tr': v = 1. - v setattr(material, _k, v) else: v = list(map(lambda x: float(x), v)) setattr(material, _k, v) if not material.map: material.map = Image(folder + '/empty.png').texture material.texture_ratio = 0.0 mesh = Mesh(geometry, material) return mesh