4
$\begingroup$

I'm developing an addon that requires selecting nodes (represented as vertices with instanced spheres) and beams (represented as edges thickened using a curve profile), all within a simple Geometry Nodes setup.

The issue is that when I enter Edit Mode to select nodes (vertices) or beams (edges), the selection isn't visible in Solid Mode—selected vertices don't visibly change, making it hard to see what’s selected.

Ideally, I’d like to highlight selected nodes by increasing the size of the instanced spheres or changing their color (e.g., turning them green). Currently, I’m using green wireframes to indicate selection, but it would be great if the entire sphere could change color instead.

Is there any way to achieve this, or is Geometry Nodes not well-suited for handling selection-based visual changes? If this is not possible with Geometry Nodes alone, maybe there is some workaround with the combination of python, maybe with a Modal operator timer that checks selected nodes and access the corresponding sphere instances in the GN and manipulate them?

enter image description here

enter image description here

$\endgroup$
1
  • 2
    $\begingroup$ Interesting question. Watching $\endgroup$ Commented Mar 6 at 10:46

2 Answers 2

5
$\begingroup$

Unfortunately Geometry Nodes alone have no capabilities in affecting the visual aspect directly and without affecting the geometry of the scene. Meaning: you can spawn any geometry you like, you can join it with the rest using a switch based on "Is Viewport" node, and you can use the materials to control the color, assuming the viewport settings (that geometry nodes can't access) allow for that.

Moreover, this is by design: in a discussion with Blender devs about gizmos, they concluded the number of gizmo colors is limited by design, to not be confusing to the user and be a part of the overall color theme.

$\endgroup$
4
  • 1
    $\begingroup$ Also, I don't think it's possible to have "interactive" nodes. It's possible to have "tool" nodes that are selection aware, but they're always activated "once on demand" not always active. $\endgroup$ Commented Mar 6 at 11:25
  • $\begingroup$ Thank you for confirming this. How about running a modal operator that will do access and manipulate those spheres in the GN tree? I'd be open to a workaround $\endgroup$ Commented Mar 6 at 11:34
  • $\begingroup$ I updated my answer, and despite my workaround effort it seems it is really not possible at the moment to do this. $\endgroup$ Commented Mar 8 at 2:07
  • $\begingroup$ Whooops found a way! Now it works also for extrusion! :D $\endgroup$ Commented Mar 8 at 15:49
3
$\begingroup$

You can use a vertex group to store the selected vertices and then assign the Instance on Points node's Selection socket to display the instances corresponding to each vertex and have a modal operator in the background listen to the vertices selected.

enter image description here

enter image description here

This is the sample modal operator that when run, will listen in the background of all selected vertices.

import bpy import bmesh import re class OBJECT_OT_VertexSelectionModalOperator(bpy.types.Operator): bl_idname = "wm.vertex_selection_modal_operator" bl_label = "Vertex Selection Modal Operator" bl_options = {'INTERNAL', 'UNDO'} _timer = None _handler = None _last_selected_indices = set() @classmethod def is_running(cls): return cls._handler is not None def modal(self, context, event): obj = context.object if not obj or obj.type != 'MESH' or obj.mode != 'EDIT': return {'PASS_THROUGH'} if event.type == 'TIMER': self.update_vertex_data(context) return {'PASS_THROUGH'} def invoke(self, context, event): cls = self.__class__ if cls._handler is not None: return {'CANCELLED'} wm = context.window_manager if cls._timer is None: cls._timer = wm.event_timer_add(0.01, window=context.window) wm.modal_handler_add(self) cls._handler = self return {'RUNNING_MODAL'} def set_selected_vertices(self, obj, vertex_group): node_tree = next((nt for nt in bpy.data.node_groups), None) mod = next((m for m in obj.modifiers if m.type == 'NODES' and m.node_group == node_tree), None) for key in mod.keys(): match = re.match(r"(.+)_attribute_name$", key) if match: base_socket_name = match.group(1) attribute_toggle_key = f"{base_socket_name}_use_attribute" if attribute_toggle_key in mod.keys(): mod[attribute_toggle_key] = True mod[key] = vertex_group def assign_vertices_to_group_in_edit_mode(self, obj, vg_name, vertex_indices, weight=1.0): bm = bmesh.from_edit_mesh(obj.data) vg = obj.vertex_groups.get(vg_name) or obj.vertex_groups.new(name=vg_name) if not bm.verts.layers.deform: deform_layer = bm.verts.layers.deform.new() else: deform_layer = bm.verts.layers.deform.active for v in bm.verts: if vg.index in v[deform_layer]: del v[deform_layer][vg.index] for i in vertex_indices: if i < len(bm.verts): bm.verts[i][deform_layer][vg.index] = weight bmesh.update_edit_mesh(obj.data) obj.data.update() def update_vertex_data(self, context): obj = context.object if obj is None or obj.type != 'MESH' or obj.mode != 'EDIT': return bm = bmesh.from_edit_mesh(obj.data) bm.verts.ensure_lookup_table() selected_verts = [v.index for v in bm.verts if v.select] if set(selected_verts) != self._last_selected_indices: self._last_selected_indices = set(selected_verts) self.assign_vertices_to_group_in_edit_mode(obj, "selected_vertices", selected_verts) def register(): bpy.utils.register_class(OBJECT_OT_VertexSelectionModalOperator) def unregister(): bpy.utils.unregister_class(OBJECT_OT_VertexSelectionModalOperator) if __name__ == "__main__": register() bpy.ops.wm.vertex_selection_modal_operator('INVOKE_DEFAULT') 
$\endgroup$
1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.