3
$\begingroup$

I don't understand why the vlist is empty after execution. I can visually see that several vertices were selected, if I use the 3d Viewport equivalent of bpy.ops.mesh.select_non_manifold() in Edit Mode which is Select > Select All by Trait > Non Manifold before running the script (it lists the proper vertices that I select through the UI, but not on its own).

o=bpy.context.selected_objects[0]
m = bmesh.new()
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_non_manifold()
m.from_mesh(o.data)
m.verts.ensure_lookup_table()

vlist=[]
for v in m.verts:
    if v.select:
        vlist.append(v)
print(vlist)
$\endgroup$
4
  • 1
    $\begingroup$ That's actually a good point. Apparently we have to do bpy.ops.object.mode_set(mode='OBJECT') after selection and then you can optionally get back into Edit Mode if you need by to using bpy.ops.object.mode_set(mode='EDIT') but not necessary. Maybe that's exactly what Select > Select All by Trait > Non Manifold does. $\endgroup$ Jan 18, 2023 at 4:17
  • 1
    $\begingroup$ Using bmesh you can get the non-manifolds by item.is_manifold BMVERT regardless of the previously selection. Change if v.select: to if not v.is_manifold:. No need for bpy.ops.mesh.select_non_manifold() anymore but it doesn´t trouble. $\endgroup$
    – relaxed
    Jan 18, 2023 at 16:26
  • $\begingroup$ @relaxed -- oddly, all verts are reported as is_manifold (True), including those that aren't! Scratching me head here.... $\endgroup$
    – james_t
    Jan 18, 2023 at 18:10
  • $\begingroup$ I assume that you have made changes in editmode and ran code without toggling to objectmode. Changes have not passed to o.data when bmesh is created from object. Try bpy.ops.object.mode_set(mode='OBJECT') in first line of script for updating, or remove m = bmesh.new() and m.from_mesh(o.data) and insert m = bmesh.from_edit_mesh(o.data) below editmode line to get bmesh from object in editmode. $\endgroup$
    – relaxed
    Jan 19, 2023 at 13:18

4 Answers 4

2
$\begingroup$

Just a clean version of the comments above

import bpy
import bmesh

o=bpy.context.selected_objects[0]
bpy.ops.object.mode_set(mode='EDIT')
m = bmesh.from_edit_mesh(o.data)

m.verts.ensure_lookup_table()
vlist=[]
for v in m.verts:
    if not v.is_manifold:
        vlist.append(v)
print(vlist)
$\endgroup$
2
  • $\begingroup$ I don't know why is_manifold is broken. My output: [] $\endgroup$
    – james_t
    Jan 19, 2023 at 14:52
  • $\begingroup$ A mystery to me. Just tested in 2.93.7, 3.3.2 and 3.4.1 (Window) and it´s fine. $\endgroup$
    – relaxed
    Jan 19, 2023 at 17:34
3
$\begingroup$

The Blender ApI documentations says that

from_mesh(mesh)
Initialize this bmesh from existing mesh datablock.

bmesh.from_edit_mesh(mesh):
Return a BMesh from this mesh, currently the mesh must already be in editmode.

So the cause is that your script is using unedited mesh data.

o=bpy.context.selected_objects[0]
m = bmesh.new()
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_non_manifold()

bpy.ops.object.editmode_toggle()


m.from_mesh(o.data)
m.verts.ensure_lookup_table()

vlist=[]
for v in m.verts:
    if v.select:
        vlist.append(v)
print(vlist)

m.free()
$\endgroup$
3
$\begingroup$

You don't need the ensure_lookup_table() call, which is only needed if the BMVertSeq changes. Apparently the selection doesn't update until you change back to Object Mode after the selection with bpy.ops.mesh.select_non_manifold() by doing bpy.ops.object.mode_set(mode='OBJECT'). Also you have to be careful because you are only appending the reference of the pointers to the vertices which are only temporary and get disposed after bmesh.free() is called. So it is best you store the vertex indices, which you can then use to easily access any vertex at any time using bpy.context.object.data.vertices[index].

import bpy
import bmesh

o=bpy.context.selected_objects[0]
m = bmesh.new()
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_non_manifold()
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='EDIT')
m.from_mesh(o.data)
m.verts.ensure_lookup_table()

vlist=[]
for v in m.verts:
    if v.select:
        vlist.append(v.index)
print(vlist)

m.free()
$\endgroup$
2
  • 1
    $\begingroup$ Back an forth between modes and throw salt over my shoulder. That's my arcane blender! $\endgroup$
    – james_t
    Jan 19, 2023 at 14:45
  • $\begingroup$ hahaha i like markus answer! we learn everyday :) $\endgroup$ Jan 19, 2023 at 14:54
3
$\begingroup$

You don't need to toggle Edit/Object mode:

import bpy, bmesh
from bpy import context as C

me = C.object.data
bm = bmesh.from_edit_mesh(me)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.select_non_manifold()
print([v.index for v in bm.verts if v.select])
$\endgroup$
1
  • 2
    $\begingroup$ and perhaps bpy.ops.mesh.select_all(action='DESELECT') instead of the for loop? $\endgroup$
    – james_t
    Jan 19, 2023 at 14:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .