def surf2mesh(S, P=(0, 0, 0), D=(0, 0, 0), wire=False): color = "#ffff00" points, polylist = S.polylist() #Conversion para quethreejs la entienda polylist = list(polylist) lpoly = [] lpoints = [] for l in points: lpoints.append(list(l)) for l in polylist: lpoly.append(list(map(int, l))) vertices = lpoints faces = lpoly # Map the vertex colors into the 'color' slot of the faces # Map the normals nfaces = [] for f in faces: p0 = points[f[0]] p1 = points[f[1]] p2 = points[f[2]] v0 = array(p1) - array(p0) v1 = array(p2) - array(p0) v3 = cross(v0, v1) v3 = tuple(v3 / sqrt(v3[0]**2 + v3[1]**2 + v3[2]**2)) nfaces.append(f + [v3, color, None]) # Create the geometry: surfaceGeometry = py3js.Geometry( vertices=vertices, faces=nfaces, #colors=vertexcolors ) #surfaceGeometry = py3js.SphereGeometry(radius=300, widthSegments=32, heightSegments=24) if wire: surfaceGeometry = py3js.WireframeGeometry(surfaceGeometry) # Calculate normals per face, for nice crisp edges: surfaceGeometry.exec_three_obj_method('computeFaceNormals') surfaceMaterial = py3js.MeshPhongMaterial(color=color, ambient="#050505", specular="#ffffff", shininess=15, emissive="#000000", side='DoubleSide', transparent=True, opacity=.8) #surfaceMaterial = py3js.MeshLambertMaterial(color='red',side='DoubleSide') # Create a mesh. Note that the material need to be told to use the vertex colors. surfaceMesh = py3js.Mesh( geometry=surfaceGeometry, material=surfaceMaterial, ) surfaceMesh.rotation = *D, "ZYX" surfaceMesh.position = tuple(P) return surfaceMesh
def to_surf_mesh(actor, surf, mapper, prop, add_attr={}): """Convert a pyvista surface to a buffer geometry. General Notes ------------- * THREE.BufferGeometry expects position and index attributes representing a triangulated mesh points and face indices or just a position array representing individual faces of a mesh. * The normals attribute is needed for physically based rendering, but not for the other mesh types. * Colors must be a RGB array with one value per point. Shading Notes ------------- To match VTK, the following materials are used to match VTK's shading: * MeshPhysicalMaterial when physically based rendering is enabled * MeshPhongMaterial when physically based rendering is disabled, but lighting is enabled. * MeshBasicMaterial when lighting is disabled. """ # convert to an all-triangular surface if surf.is_all_triangles(): trimesh = surf else: trimesh = surf.triangulate() position = array_to_float_buffer(trimesh.points) # convert to minimum index type face_ind = trimesh.faces.reshape(-1, 4)[:, 1:] index = cast_to_min_size(face_ind, trimesh.n_points) attr = { 'position': position, 'index': index, } if prop.GetInterpolation(): # something other than flat shading attr['normal'] = buffer_normals(trimesh) # extract point/cell scalars for coloring colors = None scalar_mode = mapper.GetScalarModeAsString() if scalar_mode == 'UsePointData': colors = map_scalars(mapper, trimesh.point_data.active_scalars) elif scalar_mode == 'UseCellData': # special handling for RGBA if mapper.GetColorMode() == 2: scalars = trimesh.cell_data.active_scalars.repeat(3, axis=0) scalars = scalars.astype(np.float32, copy=False) colors = scalars[:, :3] / 255 # ignore alpha else: # must repeat for each triangle scalars = trimesh.cell_data.active_scalars.repeat(3) colors = map_scalars(mapper, scalars) position = array_to_float_buffer(trimesh.points[face_ind]) attr = {'position': position} # add colors to the buffer geometry attributes if colors is not None: attr['color'] = array_to_float_buffer(colors) # texture coordinates t_coords = trimesh.active_t_coords if t_coords is not None: attr['uv'] = array_to_float_buffer(t_coords) # TODO: Convert PBR textures # base_color_texture = prop.GetTexture("albedoTex") # orm_texture = prop.GetTexture("materialTex") # anisotropy_texture = prop.GetTexture("anisotropyTex") # normal_texture = prop.GetTexture("normalTex") # emissive_texture = prop.GetTexture("emissiveTex") # coatnormal_texture = prop.GetTexture("coatNormalTex") if prop.GetNumberOfTextures(): # pragma: no cover warnings.warn( 'pythreejs converter does not support PBR textures (yet).') # create base buffer geometry surf_geo = tjs.BufferGeometry(attributes=attr) # add texture to the surface buffer if available texture = actor.GetTexture() tjs_texture = None if texture is not None: wrapped_tex = pv.wrap(texture.GetInput()) data = wrapped_tex.active_scalars dim = (wrapped_tex.dimensions[0], wrapped_tex.dimensions[1], data.shape[1]) data = data.reshape(dim) fmt = "RGBFormat" if data.shape[1] == 3 else "RGBAFormat" # Create data texture and catch invalid warning with warnings.catch_warnings(): warnings.filterwarnings("ignore", message="Given trait value dtype") tjs_texture = tjs.DataTexture(data=data, format="RGBFormat", type="UnsignedByteType") # these attributes are always used regardless of the material shared_attr = { 'vertexColors': get_coloring(mapper, trimesh), 'wireframe': prop.GetRepresentation() == 1, 'opacity': prop.GetOpacity(), 'wireframeLinewidth': prop.GetLineWidth(), # 'side': 'DoubleSide' # enabling seems to mess with textures } if colors is None: shared_attr['color'] = color_to_hex(prop.GetColor()) if tjs_texture is not None: shared_attr['map'] = tjs_texture else: shared_attr['side'] = 'DoubleSide' if prop.GetOpacity() < 1.0: shared_attr['transparent'] = True if prop.GetInterpolation() == 3: # using physically based rendering material = tjs.MeshPhysicalMaterial(flatShading=False, roughness=prop.GetRoughness(), metalness=prop.GetMetallic(), reflectivity=0, **shared_attr, **add_attr) elif prop.GetLighting(): # specular disabled to fix lighting issues material = tjs.MeshPhongMaterial( shininess=0, flatShading=prop.GetInterpolation() == 0, specular=color_to_hex((0, 0, 0)), reflectivity=0, **shared_attr, **add_attr) else: # no lighting material = tjs.MeshBasicMaterial(**shared_attr, **add_attr) return tjs.Mesh(geometry=surf_geo, material=material)
def __initialize_mesh(self): drawable_geometry = self.__get_drawable_from_boundary() #No color under textures or materials if len(self.geometry.material) != 0 or self.geometry.texture is not None: vertexEnum = 'NoColors' else: vertexEnum = 'FaceColors' materials = [] #LambertMaterial is a material for non-shiny surfaces, without specular highlights. if len(self.geometry.material) == 0: #No material or texture material_geometry = three.MeshLambertMaterial( map = self.getTexture(self.texture), polygonOffset=True, polygonOffsetFactor=1, polygonOffsetUnits=1, flatShading = True, opacity = 1., transparent = False, side = 'DoubleSide', wireframe=False, vertexColors = vertexEnum) materials = material_geometry else: for m in self.geometry.material: if self.geometry.smoothness: material_geometry = three.MeshLambertMaterial( map=self.getTexture(self.geometry.material[m]["map_kd"]), color=self.color(self.geometry.material[m]["kd"]), emissiveIntensity=self.geometry.material[m]["ke"], specular=self.color(self.geometry.material[m]["ks"]), shininess=self.geometry.material[m]["ns"], transparence=self.geometry.material[m]["transparence"], opacity=self.geometry.material[m]["opacity"], emissiveMap=self.getTexture(self.geometry.material[m]["map_ke"]), alphaMap=self.getTexture(self.geometry.material[m]["map_d"]), specularMap=self.getTexture(self.geometry.material[m]["map_ks"]), bumpMap=self.getTexture(self.geometry.material[m]["bump"]), normalMap=self.getTexture(self.geometry.material[m]["norm"]), refractionRatio=self.geometry.material[m]["ni"] ) else: material_geometry = three.MeshPhongMaterial( map = self.getTexture(self.geometry.material[m]["map_kd"]), color = self.color(self.geometry.material[m]["kd"]), emissiveIntensity = self.geometry.material[m]["ke"], specular = self.color(self.geometry.material[m]["ks"]), shininess =self.geometry.material[m]["ns"], transparence = self.geometry.material[m]["transparence"], opacity = self.geometry.material[m]["opacity"], emissiveMap = self.getTexture(self.geometry.material[m]["map_ke"]), alphaMap = self.getTexture(self.geometry.material[m]["map_d"]), specularMap = self.getTexture(self.geometry.material[m]["map_ks"]), bumpMap = self.getTexture(self.geometry.material[m]["bump"]), normalMap = self.getTexture(self.geometry.material[m]["norm"]), refractionRatio = self.geometry.material[m]["ni"] ) materials.append(material_geometry) mesh1 = three.Mesh( geometry=drawable_geometry, material=materials, position=[0, 0, 0] ) return mesh1
def visualise(mesh, geometric_field, number_of_dimensions, xi_interpolation, dependent_field=None, variable=None, mechanics_animation=False, colour_map_dependent_component_number=None, cmap='gist_rainbow', resolution=1, node_labels=False): if number_of_dimensions != 3: print( 'Warning: Only visualisation of 3D meshes is currently supported.') return if xi_interpolation != [1, 1, 1]: print( 'Warning: Only visualisation of 3D elements with linear Lagrange \ interpolation along all coordinate directions is currently \ supported.') return view_width = 600 view_height = 600 debug = False if debug: vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] faces = [[0, 1, 3], [0, 3, 2], [0, 2, 4], [2, 6, 4], [0, 4, 1], [1, 4, 5], [2, 3, 6], [3, 7, 6], [1, 5, 3], [3, 5, 7], [4, 6, 5], [5, 6, 7]] vertexcolors = [ '#000000', '#0000ff', '#00ff00', '#ff0000', '#00ffff', '#ff00ff', '#ffff00', '#ffffff' ] else: # Get mesh topology information. num_nodes = mesh_tools.num_nodes_get(mesh, mesh_component=1) node_nums = list(range(1, num_nodes + 1)) num_elements, element_nums = mesh_tools.num_element_get( mesh, mesh_component=1) # Convert geometric field to a morphic mesh and export to json mesh = mesh_tools.OpenCMISS_to_morphic(mesh, geometric_field, element_nums, node_nums, dimension=3, interpolation='linear') vertices, faces, _, xi_element_nums, xis = get_faces( mesh, res=resolution, exterior_only=True, include_xi=True) vertices = vertices.tolist() faces = faces.tolist() centroid = np.mean(vertices, axis=0) max_positions = np.max(vertices, axis=0) min_positions = np.min(vertices, axis=0) range_positions = max_positions - min_positions if (dependent_field is not None) and (colour_map_dependent_component_number is not None): solution = np.zeros(xis.shape[0]) for idx, (xi, xi_element_num) in enumerate(zip(xis, xi_element_nums)): solution[idx] = mesh_tools.interpolate_opencmiss_field_xi( dependent_field, xi, element_ids=[xi_element_num], dimension=3, deriv=1)[colour_map_dependent_component_number - 1] minima = min(solution) maxima = max(solution) import matplotlib norm = matplotlib.colors.Normalize(vmin=minima, vmax=maxima, clip=True) mapper = cm.ScalarMappable(norm=norm, cmap=cm.get_cmap(name=cmap)) vertex_colors = np.zeros((len(vertices), 3), dtype='float32') for idx, v in enumerate(solution): vertex_colors[idx, :] = mapper.to_rgba(v, alpha=None)[:3] # else: # raise ValueError('Visualisation not supported.') else: vertex_colors = np.tile(np.array([0.5, 0.5, 0.5], dtype='float32'), (len(vertices), 1)) geometry = pjs.BufferGeometry(attributes=dict( position=pjs.BufferAttribute(vertices, normalized=False), index=pjs.BufferAttribute( np.array(faces).astype(dtype='uint16').ravel(), normalized=False), color=pjs.BufferAttribute(vertex_colors), )) if mechanics_animation: deformed_vertices = np.zeros((xis.shape[0], 3), dtype='float32') for idx, (xi, xi_element_num) in enumerate(zip(xis, xi_element_nums)): deformed_vertices[idx, :] = \ mesh_tools.interpolate_opencmiss_field_xi( dependent_field, xi, element_ids=[xi_element_num], dimension=3, deriv=1)[0][:3] geometry.morphAttributes = { 'position': [ pjs.BufferAttribute(deformed_vertices), ] } geometry.exec_three_obj_method('computeFaceNormals') geometry.exec_three_obj_method('computeVertexNormals') surf1 = pjs.Mesh(geometry, pjs.MeshPhongMaterial(color='#ff3333', shininess=150, morphTargets=True, side='FrontSide'), name='A') surf2 = pjs.Mesh(geometry, pjs.MeshPhongMaterial(color='#ff3333', shininess=150, morphTargets=True, side='BackSide'), name='B') surf = pjs.Group(children=[surf1, surf2]) # camera = pjs.PerspectiveCamera( # fov=20, position=[range_positions[0] * 10, # range_positions[1] * 10, # range_positions[2] * 10], # width=view_width, # height=view_height, near=1, # far=max(range_positions) * 10) camera = pjs.PerspectiveCamera(position=[ range_positions[0] * 3, range_positions[1] * 3, range_positions[2] * 3 ], aspect=view_width / view_height) camera.up = [0, 0, 1] camera.lookAt(centroid.tolist()) scene3 = pjs.Scene(children=[ surf1, surf2, camera, pjs.DirectionalLight(position=[3, 5, 1], intensity=0.6), pjs.AmbientLight(intensity=0.5) ]) axes = pjs.AxesHelper(size=range_positions[0] * 2) scene3.add(axes) A_track = pjs.NumberKeyframeTrack( name='scene/A.morphTargetInfluences[0]', times=[0, 3], values=[0, 1]) B_track = pjs.NumberKeyframeTrack( name='scene/B.morphTargetInfluences[0]', times=[0, 3], values=[0, 1]) pill_clip = pjs.AnimationClip(tracks=[A_track, B_track]) pill_action = pjs.AnimationAction(pjs.AnimationMixer(scene3), pill_clip, scene3) renderer3 = pjs.Renderer( camera=camera, scene=scene3, controls=[pjs.OrbitControls(controlling=camera)], width=view_width, height=view_height) display(renderer3, pill_action) else: geometry.exec_three_obj_method('computeFaceNormals') geometry.exec_three_obj_method('computeVertexNormals') surf1 = pjs.Mesh(geometry=geometry, material=pjs.MeshLambertMaterial( vertexColors='VertexColors', side='FrontSide')) # Center the cube. surf2 = pjs.Mesh(geometry=geometry, material=pjs.MeshLambertMaterial( vertexColors='VertexColors', side='BackSide')) # Center the cube. surf = pjs.Group(children=[surf1, surf2]) camera = pjs.PerspectiveCamera(position=[ range_positions[0] * 3, range_positions[1] * 3, range_positions[2] * 3 ], aspect=view_width / view_height) camera.up = [0, 0, 1] camera.lookAt(centroid.tolist()) # if perspective: # camera.mode = 'perspective' # else: # camera.mode = 'orthographic' lights = [ pjs.DirectionalLight(position=[ range_positions[0] * 16, range_positions[1] * 12, range_positions[2] * 17 ], intensity=0.5), pjs.AmbientLight(intensity=0.8), ] orbit = pjs.OrbitControls(controlling=camera, screenSpacePanning=True, target=centroid.tolist()) scene = pjs.Scene() axes = pjs.AxesHelper(size=max(range_positions) * 2) scene.add(axes) scene.add(surf1) scene.add(surf2) scene.add(lights) if node_labels: # Add text labels for each mesh node. v, ids = mesh.get_node_ids(group='_default') for idx, v in enumerate(v): text = make_text(str(ids[idx]), position=(v[0], v[1], v[2])) scene.add(text) # Add text for axes labels. x_axis_label = make_text('x', position=(max(range_positions) * 2, 0, 0)) y_axis_label = make_text('y', position=(0, max(range_positions) * 2, 0)) z_axis_label = make_text('z', position=(0, 0, max(range_positions) * 2)) scene.add(x_axis_label) scene.add(y_axis_label) scene.add(z_axis_label) renderer = pjs.Renderer(scene=scene, camera=camera, controls=[orbit], width=view_width, height=view_height) camera.zoom = 1 display(renderer) return vertices, faces