Your solution is great except that I am hitting a wall here. It seems to me that the ndarray is not updated if the selection changes while in edit mode. At least that is the case when testing this stuff inside the internal text editor/
Going in an out of the edit mode resolves th eissue but not optimum. Do you know any reasonable way to update the array properly without changing modes?
@kaio I’m using the bmesh.from_edit_mesh method and I still have to exit and re-enter edit mode to get it to update. Can you give an example of how to get synced selection? I’ve been searching for two days and can’t find anything. I almost got something working using bmesh.select_history but it only “saw” and updated click selection. Box selections didn’t register at all…
Coming from MaxScript I gotta say I find the Blender API very difficult already, but the bmesh stuff is especially hard to figure out. I just wish there was a context.mesh.selected_vertices like almost everything else in Blender has since all I really want to do is track selection.
select_history isn’t actually meant to store selections, only to keep track of the last, singular element selected, which blender calls the active element. Region based selections can never add to this because only one element can be added to the history at a time. For selections in general you need to access the select property of the bmesh elements.
By synced selection I mean the selection state of elements on the bmesh mirrors what you see in the viewport.
from bmesh import from_edit_mesh
bm = from_edit_mesh(bpy.context.object.data)
vsel = [v.index for v in bm.verts if v.select]
if __name__ == '__main__':
Thank you. This is the best explanation of select_history I’ve seen so far.
I swear I was doing the list comprehension just like your example but couldn’t get an updated return without leaving and re-entering Edit Mode. But it seems to be working now. So, thanks again. That was really helpful
Updates the display in 3D window if you add new vertices, or change the selection without having to exit and re-enter Edit mode, something that you cannot do via python in Animation Nodes for instance. Hope this helps.
You might like to use a line like this:
if isinstance(v1, bmesh.types.BMVert):
To check that v1 in the first section of code is actually a vertex, not an edge, or face…
It’s tangentially worth noting that bm.select_history only keeps references to elements that were selected using mesh.select (single click on an element). Elements selected with lasso, box, circle, etc will not show up, which is somewhat understandable given that a bulk selection can’t be enumerated per se, but unfortunate nonetheless since it requires a bunch of edge-case sniffing if you’re going to use it. It’s especially maddening that bulk selection methods don’t add to select_history even if you only select a single element.
I feel like, as a design decision- they could have just dumped the bulk selection into select_history in any order (since the user’s intent with a bulk selection was clearly not concerned with order) and it would have covered more edge cases, but that’s how it is i guess.
I couldn’t agree with you more, however it is possible to use something like:
verts = [v for v in bm.verts if v.select]
The annoying thing here is that you do not know the order, other than knowing that the list is in the order you placed the vertices in the blend file. So, if I want to know which is the middle vertex on this:
If I select them one at a time I know - it’s the white one I selected last, if I bulk select them I have no idea…
So can we have bulk selections added to the select_history please?
The real problem is with existing operators that rely on select_history. For example, If you try to target weld vertices with the ‘last’ option set, it just fails if you used bulk selection as your last operation. From the users perspective, that bulk selection WAS the last selection so when it fails it’s a bad experience.
These Blender design choices are making the life of an add-on dev unnecessarily complicated.
bmesh doesn’t have a list of which components are selected.
bmesh doesn’t have foreach methods to quickly build such a list.
object.data.vertices has both, but it doesn’t update when the selection changes in Edit mode.
bmesh.select_history has a list but doesn’t include box/lasso/circle/other selected vertices.
The end result is that add-on devs have to…
loop over the entire bmesh with a list comprehension (slow on dense meshes)
or do hacks like mode switching or ob.update_from_editmode() to update the object.data (extremely expensive for dense meshes which defeats the purpose of wanting to use foreach with numpy because the slow list comprehension will be faster)
or re-implement and replace Blender functions and tools in their own python scripts and manually handle all tracking themselves (if you’re crazy and/or a masochist).
Is there really no faster way to get the selected vertices from a bmesh than to loop the entire mesh with a list comprehension?