def load(self, materials): name_map = { 'POSITION': 'in_position', 'NORMAL': 'in_normal', 'TEXCOORD_0': 'in_uv', 'TANGENT': 'in_tangent', 'JOINTS_0': 'in_joints', 'WEIGHTS_0': 'in_heights', 'COLOR_0': 'in_color0', } meshes = [] # Read all primitives as separate meshes for now # According to the spec they can have different materials and vertex format for primitive in self.primitives: vao = VAO(self.name, mode=primitive.mode or moderngl.TRIANGLES) # Index buffer component_type, index_vbo = self.load_indices(primitive) if index_vbo is not None: vao.index_buffer(context.ctx().buffer(index_vbo.tobytes()), index_element_size=component_type.size) attributes = {} vbos = self.prepare_attrib_mapping(primitive) for vbo_info in vbos: dtype, buffer = vbo_info.create() vao.buffer( buffer, " ".join([ "{}{}".format(attr[1], DTYPE_BUFFER_TYPE[dtype]) for attr in vbo_info.attributes ]), [name_map[attr[0]] for attr in vbo_info.attributes], ) for attr in vbo_info.attributes: attributes[attr[0]] = { 'name': name_map[attr[0]], 'components': attr[1], 'type': vbo_info.component_type.value, } bbox_min, bbox_max = self.get_bbox(primitive) meshes.append( Mesh( self.name, vao=vao, attributes=attributes, material=materials[primitive.material] if primitive.material is not None else None, bbox_min=bbox_min, bbox_max=bbox_max, )) return meshes
def plane_xz(size=(10, 10), resolution=(10, 10)) -> VAO: """ Generates a plane on the xz axis of a specific size and resolution :param size: (x, y) tuple :param resolution: (x, y) tuple :return: VAO """ sx, sz = size rx, rz = resolution dx, dz = sx / rx, sz / rz # step ox, oz = -sx / 2, -sz / 2 # start offset def gen_pos(): for z in range(rz): for x in range(rx): yield ox + x * dx yield 0 yield oz + z * dz def gen_uv(): for z in range(rz): for x in range(rx): yield x / (rx - 1) yield 1 - z / (rz - 1) def gen_normal(): for z in range(rx * rz): yield 0.0 yield 1.0 yield 0.0 def gen_index(): for z in range(rz - 1): for x in range(rx - 1): # quad poly left yield z * rz + x + 1 yield z * rz + x yield z * rz + x + rx # quad poly right yield z * rz + x + 1 yield z * rz + x + rx yield z * rz + x + rx + 1 pos_data = numpy.fromiter(gen_pos(), dtype=numpy.float32) uv_data = numpy.fromiter(gen_uv(), dtype=numpy.float32) normal_data = numpy.fromiter(gen_normal(), dtype=numpy.float32) index_data = numpy.fromiter(gen_index(), dtype=numpy.uint32) vao = VAO("plane_xz", mode=moderngl.TRIANGLES) vao.buffer(pos_data, '3f', ['in_position']) vao.buffer(uv_data, '2f', ['in_uv']) vao.buffer(normal_data, '3f', ['in_normal']) vao.index_buffer(index_data, index_element_size=4) return vao
def sphere(radius=0.5, sectors=32, rings=16) -> VAO: """ Generate a sphere :param radius: Radius or the sphere :param rings: number or horizontal rings :param sectors: number of vertical segments :return: VAO containing the sphere """ R = 1.0 / (rings - 1) S = 1.0 / (sectors - 1) vertices = [0] * (rings * sectors * 3) normals = [0] * (rings * sectors * 3) uvs = [0] * (rings * sectors * 2) v, n, t = 0, 0, 0 for r in range(rings): for s in range(sectors): y = math.sin(-math.pi / 2 + math.pi * r * R) x = math.cos(2 * math.pi * s * S) * math.sin(math.pi * r * R) z = math.sin(2 * math.pi * s * S) * math.sin(math.pi * r * R) uvs[t] = s * S uvs[t + 1] = r * R vertices[v] = x * radius vertices[v + 1] = y * radius vertices[v + 2] = z * radius normals[n] = x normals[n + 1] = y normals[n + 2] = z t += 2 v += 3 n += 3 indices = [0] * rings * sectors * 6 i = 0 for r in range(rings - 1): for s in range(sectors - 1): indices[i] = r * sectors + s indices[i + 1] = (r + 1) * sectors + (s + 1) indices[i + 2] = r * sectors + (s + 1) indices[i + 3] = r * sectors + s indices[i + 4] = (r + 1) * sectors + s indices[i + 5] = (r + 1) * sectors + (s + 1) i += 6 vbo_vertices = context.ctx().buffer( numpy.array(vertices, dtype=numpy.float32).tobytes()) vbo_normals = context.ctx().buffer( numpy.array(normals, dtype=numpy.float32).tobytes()) vbo_uvs = context.ctx().buffer( numpy.array(uvs, dtype=numpy.float32).tobytes()) vbo_elements = context.ctx().buffer( numpy.array(indices, dtype=numpy.uint32).tobytes()) vao = VAO("sphere", mode=mlg.TRIANGLES) # VBOs vao.buffer(vbo_vertices, '3f', ['in_position']) vao.buffer(vbo_normals, '3f', ['in_normal']) vao.buffer(vbo_uvs, '2f', ['in_uv']) vao.index_buffer(vbo_elements, index_element_size=4) return vao