.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "_gallery/feature_demo/multi_select.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr__gallery_feature_demo_multi_select.py: Multi-Object Selection ====================== Example demonstrating multi object selection using mouse events. Hovering the mouse over a cube will highlight it with a bounding box. Clicking on a cube will select it. Double-clicking a cube will select all the items from that group (because the group has a double-click event handler). Holding shift will add to the selection. This example keeps two materials, one for the default and one for the selected appearance. The low-level wgpu objects are associated with both the world object and the material. This means that swapping to a material that was already used (with that object) has zero overhead. .. GENERATED FROM PYTHON SOURCE LINES 17-143 .. image-sg:: /_gallery/feature_demo/images/sphx_glr_multi_select_001.webp :alt: multi select :srcset: /_gallery/feature_demo/images/sphx_glr_multi_select_001.webp :class: sphx-glr-single-img .. code-block:: Python from functools import partial from random import randint, random from rendercanvas.auto import RenderCanvas, loop import pygfx as gfx import pylinalg as la canvas = RenderCanvas() renderer = gfx.renderers.WgpuRenderer(canvas) camera = gfx.PerspectiveCamera(70, 16 / 9) camera.local.z = 400 camera.show_pos(((0, 0, 0))) controller = gfx.OrbitController(camera, register_events=renderer) scene = gfx.Scene() scene.add(gfx.AmbientLight(), camera.add(gfx.DirectionalLight())) geometry = gfx.box_geometry(40, 40, 40) default_material = gfx.MeshPhongMaterial(pick_write=True) selected_material = gfx.MeshPhongMaterial(color="#FF0000", pick_write=True) hover_material = gfx.MeshPhongMaterial(color="#FFAA00", pick_write=True) outline = gfx.BoxHelper(thickness=3, color="#fa0") scene.add(outline) selected_objects = [] def set_material(material, obj): if isinstance(obj, gfx.Mesh): obj.material = material def select(event): # when this event handler is invoked on non-leaf nodes of the # scene graph, event.target will still point to the leaf node that # originally triggered the event, so we use event.current_target # to get a reference to the node that is currently handling # the event, which can be a Mesh, a Group or None (the event root) obj = event.current_target # prevent propagation so we handle this event only at one # level in the hierarchy event.stop_propagation() # clear selection if selected_objects and "Shift" not in event.modifiers: while selected_objects: ob = selected_objects.pop() ob.traverse(partial(set_material, default_material)) # if the background was clicked, we're done if isinstance(obj, gfx.Renderer): return # set selection (group or mesh) selected_objects.append(obj) obj.traverse(partial(set_material, selected_material)) def hover(event): obj = event.target if event.type == "pointer_enter": obj.add(outline) outline.set_transform_by_object(obj, "local", scale=1.1) elif outline.parent: outline.parent.remove(outline) def random_rotation(): return la.quat_from_euler( ((random() - 0.5) / 100, (random() - 0.5) / 100, (random() - 0.5) / 100) ) initialized = False def animate(): global initialized # Render with both materials, to initialize them. if not initialized: initialized = True scene.traverse(lambda obj: set_material(selected_material, obj)) renderer.render(scene, camera) scene.traverse(lambda obj: set_material(default_material, obj)) def random_rot(obj): if hasattr(obj, "random_rotation"): obj.local.rotation = la.quat_mul(obj.random_rotation, obj.local.rotation) scene.traverse(random_rot) renderer.render(scene, camera) canvas.request_draw() if __name__ == "__main__": renderer.add_event_handler(select, "click") # Build up scene for _ in range(4): group = gfx.Group() group.random_rotation = random_rotation() group.add_event_handler(select, "double_click") scene.add(group) for _ in range(10): cube = gfx.Mesh(geometry, default_material) cube.local.position = ( randint(-200, 200), randint(-200, 200), randint(-200, 200), ) cube.random_rotation = random_rotation() cube.add_event_handler(select, "click") cube.add_event_handler(hover, "pointer_enter", "pointer_leave") group.add(cube) canvas.request_draw(animate) loop.run() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.471 seconds) .. _sphx_glr_download__gallery_feature_demo_multi_select.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: multi_select.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: multi_select.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: multi_select.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_ .. only:: html Interactive example ------------------- Try this example in your browser using Pyodide. Might not work with all examples and all devices. Check the output and your browser's console for details. .. raw:: html