def colored_quad_cloud(points, amplitude, indices, colormap="viridis", log_scale=False, cm_resolution=256, matrix=np.eye(4, dtype='f4'), color=None, name="quad"): #color = ensure_QColor(color) min_amplitude = float(amplitude.min()) max_amplitude = float(amplitude.max()) if log_scale: norm = mpl_colors.LogNorm(1, cm_resolution) else: norm = mpl_colors.Normalize(0, cm_resolution) colormap_ = getattr(cm, colormap)(norm(np.arange(cm_resolution))) cm_array = np.ascontiguousarray(colormap_ * 255, dtype=np.uint8) if color is None: effect = CustomEffects.color_map(Array.Array(ndarray=cm_array), amplitude.min(), amplitude.max()) else: effect = CustomEffects.material(color=color) return Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=indices), attribs=CustomAttribs.ColorsAttribs( vertices=Array.Array(ndarray=points), colors=Array.Array(ndarray=amplitude)), primitive_type=Geometry.PrimitiveType.TRIANGLES), effect=effect, transform=ensure_Transform(matrix), name=name)
def load_collada(filename, scale=1, matrix=np.eye(4, dtype='f4'), name="collada", bake_matrix=True, merge_actors=True, ignore_non_textured=False, invert_normals=False, type_id=-1, instance_id=-1): actors = Actors.Actors(shared_transform=ensure_Transform( np.eye(4, dtype='f4')) if bake_matrix else ensure_Transform(matrix), name=name, type_id=type_id, instance_id=instance_id) mesh = collada.Collada(filename) np_matrix = utils.to_numpy(matrix) textures_cache = {} actors_cache = {} bbox = np.full((2, 3), np.finfo('f4').max) bbox[1, :] = np.finfo('f4').min actors.all_vertices = [] actors.scale = scale for coll_geom in tqdm.tqdm(mesh.scene.objects('geometry')): for coll_prim in coll_geom.primitives(): #FIXME: stop ignoring colladas transforms if isinstance(coll_prim, collada.triangleset.BoundTriangleSet): triangles = coll_prim elif isinstance(coll_prim, collada.polylist.BoundPolylist): triangles = coll_prim.triangleset() else: LoggingManager.instance().warning( f"{type(coll_prim)} not implementend") continue textures = {} effect_signature = [] #for merging actors uniforms = {} for effect_name in triangles.material.effect.supported: value = getattr(triangles.material.effect, effect_name) if isinstance(value, collada.material.Map): texture_image = value.sampler.surface.image effect_signature.append((effect_name, texture_image.id)) if texture_image.id in textures_cache: textures[effect_name] = textures_cache[ texture_image.id] else: array = textures[effect_name] = textures_cache[ texture_image.id] = Array.Array( ndarray=utils.load_texture( texture_image.pilimage)) elif isinstance(value, tuple): uniforms[effect_name] = QColor.fromRgbF(*value) effect_signature.append((effect_name, value)) elif isinstance(value, float): uniforms[effect_name] = value effect_signature.append((effect_name, value)) elif value is not None: LoggingManager.instance().warning( f"Unsupported type {effect_name}: {type(value)}") if not textures and ignore_non_textured: continue effect_signature = frozenset(effect_signature) triangles.generateNormals() vertices = triangles.vertex.astype('f4') * scale normals = triangles.normal.astype('f4') if invert_normals: normals = normals * -1 if bake_matrix: vertices = linalg.map_points(np_matrix, vertices) normals = linalg.map_vectors(np_matrix, normals) indices = triangles.vertex_index.flatten().astype('u4') attributes_ndarrays = {"vertices": vertices, "normals": normals} indexed_vertices = vertices[triangles.vertex_index.flatten()] for i in range(3): bbox[0, i] = min(bbox[0, i], indexed_vertices[:, i].min()) bbox[1, i] = max(bbox[1, i], indexed_vertices[:, i].max()) if textures: if len(triangles.texcoordset) > 1: LoggingManager.instance().warning( f"warning, {type(coll_prim)} not implementend") orig_tc0 = triangles.texcoordset[0].astype('f4') tc0_idx = triangles.texcoord_indexset[0].flatten() if not np.all(tc0_idx == indices): assert tc0_idx.shape == indices.shape, "texcoord indices must be the same shape as vertex indices" #this will duplicate shared vertices so that we can have a separate texcoords for each triangle sharing vertices attributes_ndarrays['vertices'] = indexed_vertices attributes_ndarrays['normals'] = normals[ triangles.normal_index.flatten()] indices = np.arange(indices.shape[0], dtype=indices.dtype) uv = orig_tc0[tc0_idx] else: uv = np.empty((vertices.shape[0], 2), 'f4') uv[indices] = orig_tc0[tc0_idx] attributes_ndarrays['texcoords0'] = uv attribs = CustomAttribs.TexcoordsAttribs( vertices=Array.Array( ndarray=attributes_ndarrays['vertices']), normals=Array.Array( ndarray=attributes_ndarrays['normals']), texcoords0=Array.Array( ndarray=attributes_ndarrays['texcoords0'])) #FIXME: bind collada uniforms if present effect = CustomEffects.textured_material(textures) else: attribs = Geometry.Attribs( vertices=Array.Array( ndarray=attributes_ndarrays['vertices']), normals=Array.Array( ndarray=attributes_ndarrays['normals'])) #FIXME: bind other uniforms if present effect = CustomEffects.material(color=uniforms['diffuse'], back_color=uniforms['diffuse']) if invert_normals: indices = indices.reshape((indices.shape[0] // 3), 3)[:, [0, 2, 1]].flatten() if merge_actors and effect_signature in actors_cache: actor = actors_cache[effect_signature] actor_attributes = actor.geometry.attribs.get_attributes() n_vertices_before = actor_attributes['vertices'].shape[0] for attr_name, value in actor_attributes.items(): value.set_ndarray( np.vstack( (value.ndarray, attributes_ndarrays[attr_name]))) actor.geometry.indices.set_ndarray( np.hstack((actor.geometry.indices.ndarray, indices + n_vertices_before))) else: geometry = Geometry.Geometry( indices=Array.Array(ndarray=indices), attribs=attribs) actor = actors.addActor( Actors.Actor(geometry=geometry, effect=effect, transform=actors.shared_transform, name=f"{name}_{coll_geom.original.id}", type_id=type_id, instance_id=instance_id)) actors_cache[effect_signature] = actor actors.all_vertices.append( actor.geometry.attribs.vertices ) #if in merge actor mode, vertices are already there actors.bbox = bbox return actors