Instanced Mesh Visual#

Show usage of the InstancedMesh visual and its filters.

instanced mesh visual
Downloading data from https://raw.githubusercontent.com/vispy/demo-data/main/spot/spot.obj.gz (106 kB)

[........................                ] 60.53854 | downloading
[........................................] 100.00000 / downloading
File saved as /home/runner/.vispy/data/spot/spot.obj.gz.
Downloading data from https://raw.githubusercontent.com/vispy/demo-data/main/spot/spot.png (77 kB)

[.................................       ] 83.27425 | downloading
[........................................] 100.00000 / downloading
File saved as /home/runner/.vispy/data/spot/spot.png.

from itertools import cycle

import numpy as np
from scipy.spatial.transform import Rotation
from vispy import app, scene, use
from vispy.io import imread, load_data_file, read_mesh
from vispy.scene.visuals import InstancedMesh
from vispy.visuals.filters import InstancedShadingFilter, WireframeFilter, TextureFilter

# needed for instanced rendering to work
use(gl='gl+')


mesh_path = load_data_file('spot/spot.obj.gz')
texture_path = load_data_file('spot/spot.png')
vertices, faces, normals, texcoords = read_mesh(mesh_path)
texture = np.flipud(imread(texture_path))

canvas = scene.SceneCanvas(keys='interactive', bgcolor='white', show=True)
view = canvas.central_widget.add_view()

view.camera = 'arcball'
view.camera.depth_value = 10 * (vertices.max() - vertices.min())

n_instances = 100

instance_colors = np.random.rand(n_instances, 3).astype(np.float32)
instance_positions = ((np.random.rand(n_instances, 3) - 0.5) * 10).astype(np.float32)
face_colors = np.random.rand(len(faces), 3)
instance_transforms = Rotation.random(n_instances).as_matrix().astype(np.float32)

# Create a colored `MeshVisual`.
mesh = InstancedMesh(
    vertices,
    faces,
    instance_colors=instance_colors,
    face_colors=face_colors,
    instance_positions=instance_positions,
    instance_transforms=instance_transforms,
    parent=view.scene,
)


wireframe_filter = WireframeFilter(width=1)
shading_filter = InstancedShadingFilter('smooth', shininess=1)
texture_filter = TextureFilter(texture, texcoords)
mesh.attach(wireframe_filter)
mesh.attach(shading_filter)
mesh.attach(texture_filter)


def attach_headlight(view):
    light_dir = (0, 1, 0, 0)
    shading_filter.light_dir = light_dir[:3]
    initial_light_dir = view.camera.transform.imap(light_dir)

    @view.scene.transform.changed.connect
    def on_transform_change(event):
        transform = view.camera.transform
        shading_filter.light_dir = transform.map(initial_light_dir)[:3]


attach_headlight(view)


shading_cycle = cycle(['flat', None, 'smooth'])
color_cycle = cycle([None, instance_colors])
face_color_cycle = cycle([None, face_colors])


@canvas.events.key_press.connect
def on_key_press(event):
    if event.key == "t":
        texture_filter.enabled = not texture_filter.enabled
        canvas.update()
    if event.key == 's':
        shading_filter.shading = next(shading_cycle)
        canvas.update()
    if event.key == 'c':
        mesh.instance_colors = next(color_cycle)
        canvas.update()
    if event.key == 'f':
        mesh.set_data(
            vertices=vertices,
            faces=faces,
            face_colors=next(face_color_cycle),
        )
        canvas.update()
    if event.key == 'w':
        wireframe_filter.enabled = not wireframe_filter.enabled
        canvas.update()


if __name__ == "__main__":
    app.run()

Total running time of the script: (0 minutes 1.393 seconds)

Gallery generated by Sphinx-Gallery