Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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()