From 33db5c8dade0d39ccfa761319ed5e9126bd153d1 Mon Sep 17 00:00:00 2001 From: Alexandre Saint <830589+asnt@users.noreply.github.com> Date: Wed, 28 Mar 2018 22:36:47 +0200 Subject: [PATCH] Fix behavior and update interface - Adapt indexing mode to changes in MeshVisual - Add setters for texture and texcoords - Add switch for displaying the texture --- examples/basics/scene/mesh_texture.py | 11 ++- vispy/visuals/filters/mesh.py | 107 ++++++++++++++++++++------ vispy/visuals/mesh.py | 13 +++- 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/examples/basics/scene/mesh_texture.py b/examples/basics/scene/mesh_texture.py index d849d75b87..db12f1c216 100644 --- a/examples/basics/scene/mesh_texture.py +++ b/examples/basics/scene/mesh_texture.py @@ -29,8 +29,8 @@ mesh = Mesh(vertices, faces, shading=shading, color='lightgreen') view.add(mesh) -tex = TextureFilter(texture, texcoords) -mesh.attach(tex) +texture_filter = TextureFilter(texture, texcoords) +mesh.attach(texture_filter) mesh.light_dir = (0, -1, 0) initial_light_dir = view.camera.transform.imap(mesh.light_dir)[:3] @@ -43,6 +43,13 @@ def on_mouse_move(event): mesh.light_dir = transform.map(initial_light_dir)[:3] +@canvas.events.key_press.connect +def on_key_press(event): + if event.key == "t": + texture_filter.enabled = not texture_filter.enabled + mesh.update() + + canvas.show() if __name__ == "__main__": diff --git a/vispy/visuals/filters/mesh.py b/vispy/visuals/filters/mesh.py index dc1d364cc9..b8deb64856 100644 --- a/vispy/visuals/filters/mesh.py +++ b/vispy/visuals/filters/mesh.py @@ -1,48 +1,109 @@ +import weakref + +import numpy as np from vispy.gloo import Texture2D, VertexBuffer from vispy.visuals.shaders import Function, Varying -import numpy as np class TextureFilter(object): - def __init__(self, texture, texcoords): - self.texture = texture - self.texcoords = texcoords - self._texcoords = VertexBuffer(np.zeros((0, 2), dtype=np.float32)) - self._texcoord_varying = Varying('v_texcoord', 'vec2') - self.apply_coords = Function(""" - void apply_coords() { + def __init__(self, texture, texcoords, enabled=True): + """Apply a texture on a mesh. + + Parameters + ---------- + texture : (M, N) or (M, N, C) array + The 2D texture image. + texcoords : (N, 2) array + The texture coordinates. + enabled : bool + Whether the display of the texture is enabled. + """ + self.pass_coords = Function(""" + void pass_coords() { $v_texcoords = $texcoords; } """) - self.apply_texture = Function(""" void apply_texture() { - gl_FragColor *= texture2D($u_texture, $texcoord); + if ($enabled == 1) { + gl_FragColor *= texture2D($u_texture, $texcoords); + } } """) - - self.coords_expr = self.apply_coords() + self._texcoord_varying = Varying('v_texcoord', 'vec2') + self.pass_coords['v_texcoords'] = self._texcoord_varying + self.apply_texture['texcoords'] = self._texcoord_varying + self._texcoords_buffer = VertexBuffer( + np.zeros((0, 2), dtype=np.float32) + ) + self.pass_coords['texcoords'] = self._texcoords_buffer + self.coords_expr = self.pass_coords() self.texture_expr = self.apply_texture() + self._attached = False + self.enabled = enabled + self.texture = texture + self.texcoords = texcoords + + @property + def enabled(self): + """True to display the texture, False to disable.""" + return self._enabled + + @enabled.setter + def enabled(self, enabled): + self._enabled = enabled + self.apply_texture['enabled'] = 1 if enabled else 0 + + @property + def texture(self): + """The texture image.""" + return self._texture + + @texture.setter + def texture(self, texture): + self._texture = texture + self.apply_texture['u_texture'] = Texture2D(texture) + + @property + def texcoords(self): + """The texture coordinates as an (N, 2) array of floats.""" + return self._texcoords + + @texcoords.setter + def texcoords(self, texcoords): + self._texcoords = texcoords + self._update_texcoords_buffer(texcoords) + + def _update_texcoords_buffer(self, texcoords): + if not self._attached: + return + md = self._visual().mesh_data + if self._visual().shading == 'smooth' and not md.has_face_indexed_data(): + tc = texcoords + else: + tc = texcoords[md.get_faces()] + self._texcoords_buffer.set_data(tc, convert=True) + + def _on_mesh_data_updated(self, event): + self._update_texcoords_buffer(self._texcoords) + def _attach(self, visual): - # vertex shader + visual.events.data_updated.connect(self._on_mesh_data_updated) + vert_pre = visual._get_hook('vert', 'pre') vert_pre.add(self.coords_expr) - if visual.shading == 'smooth': - tc = self.texcoords - else: - tc = self.texcoords[visual.mesh_data.get_faces()] - self._texcoords.set_data(tc, convert=True) - self.apply_coords['texcoords'] = self._texcoords - self.apply_coords['v_texcoords'] = self._texcoord_varying - # fragment shader frag_post = visual._get_hook('frag', 'post') frag_post.add(self.texture_expr) - self.apply_texture['texcoord'] = self._texcoord_varying - self.apply_texture['u_texture'] = Texture2D(self.texture) + + self._attached = True + self._visual = weakref.ref(visual) + + self._update_texcoords_buffer(self._texcoords) def _detach(self, visual): visual._get_hook('vert', 'pre').remove(self.coords_expr) visual._get_hook('frag', 'post').remove(self.texture_expr) + self._attached = False diff --git a/vispy/visuals/mesh.py b/vispy/visuals/mesh.py index 2d1edfff26..41e1c90a74 100644 --- a/vispy/visuals/mesh.py +++ b/vispy/visuals/mesh.py @@ -17,6 +17,7 @@ from ..geometry import MeshData from ..color import Color, get_colormap from ..ext.six import string_types +from ..util.event import Event # Shaders for lit rendering (using phong shading) @@ -173,6 +174,11 @@ class MeshVisual(Visual): The drawing mode. **kwargs : dict Keyword arguments to pass to `Visual`. + + Events + ------ + data_updated + Emitted when the mesh data is updated. """ def __init__(self, vertices=None, faces=None, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1, 1), vertex_values=None, @@ -197,6 +203,8 @@ def __init__(self, vertices=None, faces=None, vertex_colors=None, 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._normals = None @@ -351,8 +359,7 @@ def mesh_data_changed(self): def _update_data(self): md = self.mesh_data # Update vertex/index buffers - # if self.shading == 'smooth' and not md.has_face_indexed_data(): - if self.shading == 'smooth': + if self.shading == 'smooth' and not md.has_face_indexed_data(): v = md.get_vertices() if v is None: return False @@ -443,6 +450,8 @@ def _update_data(self): self._data_changed = False + self.events.data_updated() + @property def shininess(self): """The shininess"""