def set_data(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=None, vertex_values=None, meshdata=None): """Set the mesh data Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None Values for each vertex. meshdata : instance of MeshData | None The meshdata. """ if meshdata is not None: self._meshdata = meshdata else: self._meshdata = MeshData(vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values) self._bounds = self._meshdata.get_bounds() if color is not None: self._color = Color(color) self.mesh_data_changed()
def __init__(self, vertices=None, faces=None, edges=None, vertex_colors=None, face_colors=None): MeshData.__init__(self, vertices=None, faces=None, edges=None, vertex_colors=None, face_colors=None)
def set_data(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=None, vertex_values=None, meshdata=None): """Set the mesh data Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None Values for each vertex. meshdata : instance of MeshData | None The meshdata. """ if meshdata is not None: self._meshdata = meshdata else: self._meshdata = MeshData(vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values) self._bounds = self._meshdata.get_bounds() if color is not None: self._color = Color(color) self.mesh_data_changed() if self.variable_vis: # Initialize all faces as visible if self.mode is 'lines': self._visible_verts = np.ones((faces.shape[0], 2, 1), dtype=np.int8) else: self._visible_verts = np.ones((faces.shape[0], 3, 1), dtype=np.int8) # Create visibility VertexBuffer self.vis_buffer = VertexBuffer() self.vis_buffer.set_data(self._visible_verts) self.shared_program.vert['vis_vert'] = self.vis_buffer
def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Monkey', keys='interactive') verts, faces, normals, texcoords = io.read_mesh( "../model/monkey/monkey.obj") obj = MeshData(verts, faces) self.program = gloo.Program(vert=vertex, frag=fragment) V = verts.astype('float32') F = obj.get_faces().astype('uint32') E = obj.get_edges().astype('uint32') C = np.array([(1, 1, 1, 1)]) for i in range(len(V) - 1): if i % 2 != 0: C = np.append(C, [(1, 1, 1, 1)], axis=0) else: C = np.append(C, [(0, 0, 0, 1)], axis=0) self.program['a_position'] = V self.program['a_color'] = C.astype('float32') self.F = gloo.IndexBuffer(F) self.E = gloo.IndexBuffer(E) gloo.set_viewport(0, 0, *self.physical_size) gloo.set_polygon_offset(1.0, 1.0) # intialize transformation matrix view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) projection = np.eye(4, dtype=np.float32) # set view view = translate((0, 0, -5)) self.program['u_model'] = model self.program['u_view'] = view self.program['u_projection'] = projection # bind a timer self.timer = app.Timer('auto', self.on_timer) self.theta = 0.0 self.phi = 0.0 self.timer.start() # show the canvas self.show()
def updateMesh(self, vertices=None, faces=None, colors=None, texture=None, textureCoordinates=None): # Set if vertices is not None: self._meshData.set_vertices(verts=vertices) if faces is not None: self._meshData.set_faces(faces) if colors is not None: self._meshData.set_vertex_colors(colors) # Update if vertices is not None or faces is not None: self._vertices = VertexBuffer( self._meshData.get_vertices(indexed='faces').astype( np.float32)) if faces is not None and vertices is not None: self._normals = VertexBuffer( self._meshData.get_vertex_normals(indexed='faces').astype( np.float32)) if colors is not None: self._colors = VertexBuffer( self._meshData.get_vertex_colors(indexed='faces').astype( np.float32)) if texture is not None: self._texture = Texture2D(np.array(texture, dtype=np.float32), interpolation='linear', wrapping='mirrored_repeat') if textureCoordinates is not None: textureMesh = MeshData(vertices=textureCoordinates, faces=self._meshData.get_faces()) self._textureCoordinates = VertexBuffer( textureMesh.get_vertices(indexed='faces').astype(np.float32)) # Update GPU - geometry self.shared_program.vert['position'] = self._vertices self.shared_program.vert['normal'] = self._normals # Update GPU - color if self._texture is None: self.shared_program.vert['color'] = self._colors else: self.shared_program.vert[ 'textureCoordinates'] = self._textureCoordinates self.shared_program['u_objectTexture'] = self._texture
def create_cylinder(rows, cols, r_angle=0, radius=[1.0, 1.0], length=1.0, offset=False): """Create a cylinder Parameters ---------- rows : int Number of rows. cols : int Number of columns. radius : tuple of float Cylinder radii. length : float Length of the cylinder. offset : bool Rotate each row by half a column. Returns ------- cylinder : MeshData Vertices and faces computed for a cylindrical surface. """ verts_n_faces = make_quad_arm(rows=rows, cols=cols, r_angle=r_angle, radius=radius, length=length, offset=offset) return MeshData(verts_n_faces[0], verts_n_faces[1])
def __init__(self, radius=1.0, directions=None, colors=None): # Convert spherical to cartesian points = np.array([util.tp2xyz(*x) for x in directions]) # Create mesh import scipy.spatial ch = scipy.spatial.ConvexHull(points) mesh = MeshData(vertices=ch.points, faces=ch.simplices) self._mesh = MeshVisual(vertices=mesh.get_vertices(), faces=mesh.get_faces(), vertex_colors=colors) CompoundVisual.__init__(self, [self._mesh]) self.mesh.set_gl_state(depth_test=True)
def create_quad_frame(rows, cols=8, radius=[1.0, 1.0], length=1.0, offset=False): verts, faces, colors = make_quad_frame(rows=rows, cols=cols, radius=radius, length=length, offset=offset) return (MeshData(verts, faces), colors)
def _on_data_change(self): if len(self.layer._data_view) == 0 or len(self.layer._view_faces) == 0: vertices = None faces = None vertex_values = np.array([0]) else: # Offsetting so pixels now centered # coerce to float to solve vispy/vispy#2007 # reverse order to get zyx instead of xyz vertices = np.asarray(self.layer._data_view[:, ::-1], dtype=np.float32) # due to above xyz>zyx, also reverse order of faces to fix handedness of normals faces = self.layer._view_faces[:, ::-1] vertex_values = self.layer._view_vertex_values if (vertices is not None and self.layer._ndisplay == 3 and self.layer.ndim == 2): vertices = np.pad(vertices, ((0, 0), (0, 1))) # manually detach filters when we go to 2D to avoid dimensionality issues # see comments in napari#3475. The filter is set again after set_data! if self.layer._ndisplay == 2: filt = self.node.shading_filter try: self.node.detach(filt) self.node.shading = None self.node.shading_filter = None except ValueError: # sometimes we try to detach non-attached filters, which causes a ValueError pass self.node.set_data(vertices=vertices, faces=faces, vertex_values=vertex_values) # disable normals in 2D to avoid shape errors if self.layer._ndisplay == 2: meshdata = MeshData() else: meshdata = self.node.mesh_data self._meshdata = meshdata self._on_face_normals_change() self._on_vertex_normals_change() self._on_shading_change() self.node.update() # Call to update order of translation values with new dims: self._on_matrix_change()
def add_surf(self, surf, color=SKIN_COLOR, vertex_colors=None, values=None, limits_c=None, colormap=COLORMAP, alpha=1): """Add surfaces to the visualization. Parameters ---------- surf : instance of wonambi.attr.anat.Surf surface to be plotted color : tuple or ndarray, optional 4-element tuple, representing RGB and alpha, between 0 and 1 vertex_colors : ndarray ndarray with n vertices x 4 to specify color of each vertex values : ndarray, optional vector with values for each vertex limits_c : tuple of 2 floats, optional min and max values to normalize the color colormap : str one of the colormaps in vispy alpha : float transparency (1 = opaque) """ colors, limits = _prepare_colors(color=color, values=values, limits_c=limits_c, colormap=colormap, alpha=alpha) # meshdata uses numpy array, in the correct dimension vertex_colors = colors.rgba if vertex_colors.shape[0] == 1: vertex_colors = tile(vertex_colors, (surf.n_vert, 1)) meshdata = MeshData(vertices=surf.vert, faces=surf.tri, vertex_colors=vertex_colors) mesh = SurfaceMesh(meshdata) self._add_mesh(mesh) # adjust camera surf_center = mean(surf.vert, axis=0) if surf_center[0] < 0: azimuth = 270 else: azimuth = 90 self._view.camera.azimuth = azimuth self._view.camera.center = surf_center self._surf.append(mesh)
def test_convert_meshdata(self): """Test convert_meshdata function.""" from vispy.geometry import MeshData import vispy.visuals.transforms as vist # Force creation of vertices, faces and normals : self._creation() tup = (self.vertices, self.faces) # Compare (vertices + faces) Vs. MeshData : mesh1 = convert_meshdata(*tup) mesh2 = convert_meshdata(meshdata=MeshData(*tup)) assert np.array_equal(mesh1[0], mesh2[0]) assert np.array_equal(mesh1[1], mesh2[1]) assert np.array_equal(mesh1[2], mesh2[2]) # Invert normals : inv1 = convert_meshdata(*tup, invert_normals=True)[-1] assert np.array_equal(inv1, -mesh1[-1]) # Create transformation : tr = vist.MatrixTransform() tr.rotate(90, (0, 0, 1)) convert_meshdata(*tup, transform=tr)[-1]
class VarVisMeshVisual(MeshVisual): """Variable Visibility Mesh visual Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None The values to use for each vertex (for colormapping). meshdata : instance of MeshData | None The meshdata. shading : str | None Shading to use. mode : str The drawing mode. variable_vis : bool If instance of UpdatableMeshVisual has variable visibility **kwargs : dict Keyword arguments to pass to `Visual`. """ def __init__(self, nb_boxes, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1, 1), vertex_values=None, meshdata=None, shading=None, mode='triangles', variable_vis=False, **kwargs): # Visual.__init__ -> prepare_transforms() -> uses shading if shading is not None: raise ValueError('"shading" must be "None"') self.shading = shading self._variable_vis = variable_vis if variable_vis: Visual.__init__(self, vcode=vertex_template_vis, fcode=fragment_template_vis, **kwargs) else: Visual.__init__(self, vcode=vertex_template, fcode=fragment_template, **kwargs) self.set_gl_state('translucent', depth_test=True, cull_face=False) # Define buffers self._vertices = VertexBuffer(np.zeros((0, 3), dtype=np.float32)) self._normals = None self._faces = IndexBuffer() self._normals = VertexBuffer(np.zeros((0, 3), dtype=np.float32)) self._ambient_light_color = Color((0.3, 0.3, 0.3, 1.0)) self._light_dir = (10, 5, -5) self._shininess = 1. / 200. self._cmap = get_colormap('cubehelix') self._clim = 'auto' self._mode = mode # Uniform color self._color = Color(color) # primitive mode self._draw_mode = mode # Init self._bounds = None # Note we do not call subclass set_data -- often the signatures # do no match. VarVisMeshVisual.set_data(self, vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, color=color, vertex_values=vertex_values, meshdata=meshdata) self.freeze() def set_data(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=None, vertex_values=None, meshdata=None): """Set the mesh data Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None Values for each vertex. meshdata : instance of MeshData | None The meshdata. """ if meshdata is not None: self._meshdata = meshdata else: self._meshdata = MeshData(vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values) self._bounds = self._meshdata.get_bounds() if color is not None: self._color = Color(color) self.mesh_data_changed() if self.variable_vis: # Initialize all faces as visible if self.mode is 'lines': self._visible_verts = np.ones((faces.shape[0], 2, 1), dtype=np.int8) else: self._visible_verts = np.ones((faces.shape[0], 3, 1), dtype=np.int8) # Create visibility VertexBuffer self.vis_buffer = VertexBuffer() self.vis_buffer.set_data(self._visible_verts) self.shared_program.vert['vis_vert'] = self.vis_buffer def set_visible_faces(self, idx_vis): """Set idx_vis indexes of visible_verts to "visible" (1). """ self.visible_verts[idx_vis, :, :] = 1 def set_invisible_faces(self, idx_vis): """Set idx_vis indexes of visible_verts to "invisible" (0). """ self.visible_verts[idx_vis, :, :] = 0 def update_vis_buffer(self): """Update the visibility VertexBuffer. """ self.vis_buffer.set_data(self.visible_verts) self.shared_program.vert['vis_vert'] = self.vis_buffer @property def visible_verts(self): """Bool (float) array indicating which vertices are visible (1) and which are invisible (0). """ return self._visible_verts @visible_verts.setter def visible_verts(self, visible_verts): self._visible_verts = visible_verts @property def variable_vis(self): """Bool if instance of UpdatableMeshVisual posseses variable visibility. """ return self._variable_vis @variable_vis.setter def variable_vis(self, variable_vis): raise ValueError( 'Not allowed to change "variable_vis" after initialization.')
def convert_meshdata(vertices=None, faces=None, normals=None, meshdata=None, invert_normals=False, transform=None): """Convert mesh data to be compatible with visbrain. Parameters ---------- vertices : array_like | None Vertices of the template of shape (N, 3) or (N, 3, 3) if indexed by faces. faces : array_like | None Faces of the template of shape (M, 3) normals : array_like | None The normals to each vertex, with the same shape as vertices. meshdata : VisPy.MeshData | None VisPy MeshData object. invert_normals : bool | False If the brain appear to be black, use this parameter to invert normals. transform : visPy.transform | None VisPy transformation to apply to vertices ans normals. Returns ------- vertices : array_like Vertices of shape (N, 3) faces : array_like Faces of the template of shape (M, 3) normals : array_like The normals of shape (M, 3, 3). """ # Priority to meshdata : if meshdata is not None: vertices = meshdata.get_vertices() faces = meshdata.get_faces() normals = meshdata.get_vertex_normals() logger.debug('Indexed faces normals converted // extracted') else: # Check if faces index start at zero (Matlab like): if faces.min() != 0: faces -= faces.min() # Get normals if None : if (normals is None) or (normals.ndim != 2): md = MeshData(vertices=vertices, faces=faces) normals = md.get_vertex_normals() logger.debug('Indexed faces normals converted // extracted') assert vertices.ndim == 2 # Invert normals : norm_coef = -1. if invert_normals else 1. normals *= norm_coef # Apply transformation : if transform is not None: vertices = transform.map(vertices)[..., 0:-1] normals = transform.map(normals)[..., 0:-1] # Type checking : vertices = vispy_array(vertices) faces = vispy_array(faces, np.uint32) normals = vispy_array(normals) return vertices, faces, normals
def __init__(self, parent=None, children=None, objectID=0, materialID=0, textureCoordinates=None, **kwargs): MeshData.__init__(self, **kwargs) # Set parent (None=root) self._parent = parent # Set children if children is not None: if isinstance(children, list): self._children = children else: self._children = [children] else: self._children = [] # Set IDs self._objectID = objectID self._materialID = materialID checkID(self, self._objectID) checkID(self, self._materialID) # Set empty array for unset data, ndarray for set data if self._vertices is None: self._vertices = np.empty(0, dtype=np.float32) warn('Unset vertices for object ' + self.__repr__(), category=RuntimeWarning) elif isinstance(self._vertices, list) or isinstance( self._vertices, tuple): self._vertices = np.asarray(self._vertices, dtype=np.float32) elif not isinstance(self._vertices, np.ndarray): raise ValueError('Invalid container type!') if self._faces is None: self._faces = np.empty(0, dtype=np.uint32) warn('Unset faces for object ' + self.__repr__(), category=RuntimeWarning) elif isinstance(self._faces, list) or isinstance(self._faces, tuple): self._faces = np.asarray(self._faces, dtype=np.uint32) elif not isinstance(self._faces, np.ndarray): raise ValueError('Invalid container type!') if textureCoordinates is None: self._textureCoordinates = np.zeros((len(self._vertices), 2), dtype=np.float32) warn('Unset texture coordinates for object ' + self.__repr__(), category=RuntimeWarning) elif isinstance(textureCoordinates, list) or isinstance( textureCoordinates, tuple): self._textureCoordinates = np.asarray(textureCoordinates, dtype=np.float32) elif isinstance(textureCoordinates, np.ndarray): self._textureCoordinates = textureCoordinates else: raise ValueError('Invalid container type!')
class MeshVisual(Visual): """Mesh visual Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None The values to use for each vertex (for colormapping). meshdata : instance of MeshData | None The meshdata. shading : str | None Shading to use. This uses the :class:`~vispy.visuals.filters.mesh.ShadingFilter` filter introduced in VisPy 0.7. This class provides additional features that are available when the filter is attached manually. See 'examples/basics/scene/mesh_shading.py' for an example. mode : str The drawing mode. **kwargs : dict Keyword arguments to pass to `Visual`. Notes ----- Additional functionality is available through filters. Mesh-specific filters can be found in the :mod:`vispy.visuals.filters.mesh` module. This class emits a `data_updated` event when the mesh data is updated. This is used for example by filters for synchronization. """ def __init__(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1, 1), vertex_values=None, meshdata=None, shading=None, mode='triangles', **kwargs): Visual.__init__(self, vcode=vertex_template, fcode=fragment_template, **kwargs) self.set_gl_state('translucent', depth_test=True, cull_face=False) self.events.add(data_updated=Event) # Define buffers self._vertices = VertexBuffer(np.zeros((0, 3), dtype=np.float32)) self._cmap = get_colormap('cubehelix') self._clim = 'auto' # Uniform color self._color = Color(color) # add filters for various modifiers self.shading_filter = None self.shading = shading # Init self._bounds = None # Note we do not call subclass set_data -- often the signatures # do no match. MeshVisual.set_data( self, vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values, meshdata=meshdata, color=color) # primitive mode self._draw_mode = mode self.freeze() @property def shading(self): """The shading method.""" return self._shading @shading.setter def shading(self, shading): assert shading in (None, 'flat', 'smooth') self._shading = shading if shading is None and self.shading_filter is None: # Delay creation of filter until necessary. return if self.shading_filter is None: from .filters import ShadingFilter self.shading_filter = ShadingFilter(shading=shading) else: self.shading_filter.shading = shading self.attach(self.shading_filter) def set_data(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=None, vertex_values=None, meshdata=None): """Set the mesh data Parameters ---------- vertices : array-like | None The vertices. faces : array-like | None The faces. vertex_colors : array-like | None Colors to use for each vertex. face_colors : array-like | None Colors to use for each face. color : instance of Color The color to use. vertex_values : array-like | None Values for each vertex. meshdata : instance of MeshData | None The meshdata. """ if meshdata is not None: self._meshdata = meshdata else: self._meshdata = MeshData(vertices=vertices, faces=faces, vertex_colors=vertex_colors, face_colors=face_colors, vertex_values=vertex_values) self._bounds = self._meshdata.get_bounds() if color is not None: self._color = Color(color) self.mesh_data_changed() @property def clim(self): return (self._clim if isinstance(self._clim, str) else tuple(self._clim)) @clim.setter def clim(self, clim): if isinstance(clim, str): if clim != 'auto': raise ValueError('clim must be "auto" if a string') else: clim = np.array(clim, float) if clim.shape != (2,): raise ValueError('clim must have two elements') self._clim = clim self.mesh_data_changed() @property def _clim_values(self): if isinstance(self._clim, str): # == 'auto' if self._meshdata.has_vertex_value(): clim = self._meshdata.get_vertex_values() clim = (np.min(clim), np.max(clim)) else: clim = (0, 1) else: clim = self._clim return clim @property def cmap(self): return self._cmap @cmap.setter def cmap(self, cmap): self._cmap = get_colormap(cmap) self.mesh_data_changed() @property def mode(self): """The triangle mode used to draw this mesh. Options are: * 'triangles': Draw one triangle for every three vertices (eg, [1,2,3], [4,5,6], [7,8,9) * 'triangle_strip': Draw one strip for every vertex excluding the first two (eg, [1,2,3], [2,3,4], [3,4,5]) * 'triangle_fan': Draw each triangle from the first vertex and the last two vertices (eg, [1,2,3], [1,3,4], [1,4,5]) """ return self._draw_mode @mode.setter def mode(self, m): modes = ['triangles', 'triangle_strip', 'triangle_fan'] if m not in modes: raise ValueError("Mesh mode must be one of %s" % ', '.join(modes)) self._draw_mode = m @property def mesh_data(self): """The mesh data""" return self._meshdata @property def color(self): """The uniform color for this mesh""" return self._color @color.setter def color(self, c): """Set the uniform color of the mesh This value is only used if per-vertex or per-face colors are not specified. Parameters ---------- c : instance of Color The color to use. """ if c is not None: self._color = Color(c) self.mesh_data_changed() def mesh_data_changed(self): self._data_changed = True self.update() def _update_data(self): md = self.mesh_data v = md.get_vertices(indexed='faces') if v is None: return False if v.shape[-1] == 2: v = np.concatenate((v, np.zeros((v.shape[:-1] + (1,)))), -1) self._vertices.set_data(v, convert=True) if md.has_vertex_color(): colors = md.get_vertex_colors(indexed='faces') colors = colors.astype(np.float32) elif md.has_face_color(): colors = md.get_face_colors(indexed='faces') colors = colors.astype(np.float32) elif md.has_vertex_value(): colors = md.get_vertex_values(indexed='faces') colors = colors.ravel()[:, np.newaxis] colors = colors.astype(np.float32) else: colors = self._color.rgba self.shared_program.vert['position'] = self._vertices self.shared_program['texture2D_LUT'] = self._cmap.texture_lut() \ if (hasattr(self._cmap, 'texture_lut')) else None # Position input handling if v.shape[-1] == 2: self.shared_program.vert['to_vec4'] = vec2to4 elif v.shape[-1] == 3: self.shared_program.vert['to_vec4'] = vec3to4 else: raise TypeError("Vertex data must have shape (...,2) or (...,3).") # Set the base color. # # The base color is mixed further by the material filters for texture # or shading effects. self.shared_program.vert['color_transform'] = \ _build_color_transform(colors, self._cmap, self._clim_values) if colors.ndim == 1: self.shared_program.vert['base_color'] = colors else: self.shared_program.vert['base_color'] = VertexBuffer(colors) self._data_changed = False self.events.data_updated() def _prepare_draw(self, view): if self._data_changed: if self._update_data() is False: return False self._data_changed = False def draw(self, *args, **kwds): Visual.draw(self, *args, **kwds) @staticmethod def _prepare_transforms(view): tr = view.transforms.get_transform() view.view_program.vert['transform'] = tr def _compute_bounds(self, axis, view): if self._bounds is None: return None if axis >= len(self._bounds): return (0, 0) else: return self._bounds[axis]
def __init__(self, vertices, faces, colors=None, texture=None, textureCoordinates=None, light=None, ambientMaterialConstant=0.5, diffuseMaterialConstant=0.4, specularMaterialConstant=0.3, vertexShader=defaultVertexShader, fragmentShader=defaultFragmentShader, camera=None): Visual.__init__(self, vertexShader, fragmentShader) # Culling mode (for debugging) #wrappers.set_cull_face(mode='back') # Default arguments if colors is None and texture is None: colors = np.array([(0.5, 0.5, 0.5) for index in range(vertices.shape[0])], dtype=np.float32) elif colors is not None and len(colors) is 3 and (isinstance( colors[0], float) or isinstance(colors[0], int)): colors = np.array([colors for index in range(len(vertices))], dtype=np.float32) if light is None: light = SimpleLight(self, color=(1.0, 1.0, 1.0)) else: light = light(self) # Geometry setup self._meshData = MeshData(vertices=vertices, faces=faces, vertex_colors=colors) self._vertices = None self._colors = None self._texture = None self._textureCoordinates = None self._normals = None self._draw_mode = 'triangles' self.set_gl_state('opaque', depth_test=True, cull_face=True) # Light setup self._light = light self._camera = camera self._ambientMaterialConstant = ambientMaterialConstant self._diffuseMaterialConstant = diffuseMaterialConstant self._specularMaterialConstant = specularMaterialConstant # Initial updates self.updateMesh(vertices=vertices, faces=faces, colors=colors, texture=texture, textureCoordinates=textureCoordinates) self.updateLight()
class TriangleMeshVisual(Visual): def __init__(self, vertices, faces, colors=None, texture=None, textureCoordinates=None, light=None, ambientMaterialConstant=0.5, diffuseMaterialConstant=0.4, specularMaterialConstant=0.3, vertexShader=defaultVertexShader, fragmentShader=defaultFragmentShader, camera=None): Visual.__init__(self, vertexShader, fragmentShader) # Culling mode (for debugging) #wrappers.set_cull_face(mode='back') # Default arguments if colors is None and texture is None: colors = np.array([(0.5, 0.5, 0.5) for index in range(vertices.shape[0])], dtype=np.float32) elif colors is not None and len(colors) is 3 and (isinstance( colors[0], float) or isinstance(colors[0], int)): colors = np.array([colors for index in range(len(vertices))], dtype=np.float32) if light is None: light = SimpleLight(self, color=(1.0, 1.0, 1.0)) else: light = light(self) # Geometry setup self._meshData = MeshData(vertices=vertices, faces=faces, vertex_colors=colors) self._vertices = None self._colors = None self._texture = None self._textureCoordinates = None self._normals = None self._draw_mode = 'triangles' self.set_gl_state('opaque', depth_test=True, cull_face=True) # Light setup self._light = light self._camera = camera self._ambientMaterialConstant = ambientMaterialConstant self._diffuseMaterialConstant = diffuseMaterialConstant self._specularMaterialConstant = specularMaterialConstant # Initial updates self.updateMesh(vertices=vertices, faces=faces, colors=colors, texture=texture, textureCoordinates=textureCoordinates) self.updateLight() # --- Function override --- def _prepare_transforms(self, view): view.view_program.vert['transform'] = view.get_transform() def _prepare_draw(self, view): #self.updateMesh() self.updateLight() # --- State update --- def updateMesh(self, vertices=None, faces=None, colors=None, texture=None, textureCoordinates=None): # Set if vertices is not None: self._meshData.set_vertices(verts=vertices) if faces is not None: self._meshData.set_faces(faces) if colors is not None: self._meshData.set_vertex_colors(colors) # Update if vertices is not None or faces is not None: self._vertices = VertexBuffer( self._meshData.get_vertices(indexed='faces').astype( np.float32)) if faces is not None and vertices is not None: self._normals = VertexBuffer( self._meshData.get_vertex_normals(indexed='faces').astype( np.float32)) if colors is not None: self._colors = VertexBuffer( self._meshData.get_vertex_colors(indexed='faces').astype( np.float32)) if texture is not None: self._texture = Texture2D(np.array(texture, dtype=np.float32), interpolation='linear', wrapping='mirrored_repeat') if textureCoordinates is not None: textureMesh = MeshData(vertices=textureCoordinates, faces=self._meshData.get_faces()) self._textureCoordinates = VertexBuffer( textureMesh.get_vertices(indexed='faces').astype(np.float32)) # Update GPU - geometry self.shared_program.vert['position'] = self._vertices self.shared_program.vert['normal'] = self._normals # Update GPU - color if self._texture is None: self.shared_program.vert['color'] = self._colors else: self.shared_program.vert[ 'textureCoordinates'] = self._textureCoordinates self.shared_program['u_objectTexture'] = self._texture def updateLight(self): self.shared_program.frag['ambientLight'] = self._light._ambient self.shared_program.frag[ 'ambientMaterialConstant'] = self._ambientMaterialConstant self.shared_program.frag[ 'diffuseMaterialConstant'] = self._diffuseMaterialConstant self.shared_program.frag[ 'specularMaterialConstant'] = self._specularMaterialConstant self.shared_program.frag['lightPos'] = self._light._pos self.shared_program.frag['lightColor'] = self._light._color self.shared_program.frag['cameraPos'] = np.array( self._camera._quaternion.rotate_point([0.0, 3.0, 0.0]), dtype=np.float32) self.update()