Flushing select mode.
Recommend naming a bmesh
representation of a mesh bm
and reserve mesh
or me
for a mesh.
bpy.ops.mesh
operators manipulate the mesh. A bound bmesh, ie from_edit_mesh
is still not the mesh. An edit mode mesh is what we don't have a handle on via python. Can set me.vertices
properties in edit mode, but will have no effect on the "special" edit mode instance of the mesh.
Flushing selection, or updating the bmesh will ensure the mesh used by the operator has the changes. Put it in a fit context to be operated on
If the intention is using bound bmesh
to select the geometry required by bpy.ops.mesh
operator, flush the selection before the operator call.
As mentioned in prior answer, the results of your script will change depending on selection mode. It is part of the context bpy.ops.mesh
operators use. This sets it to all.
>>> C.tool_settings.mesh_select_mode = (True, True, True)
Result of running the script in prior question in only vert, only edge, and only face selection modes. No prior selections
Will also get the desired result if we select face in face selection mode, then switch to vert select mode and run script. The simplest fix of all to use bpy.ops.mesh
with face selection from verts selection is to set one or both of faces and edges to True.
In the bmesh
docs
Selection / Flushing
As mentioned above, it is possible to create an invalid selection
state (by selecting a state and then de-selecting one of its
vertices’s for example), mostly the best way to solve this is to flush
the selection after performing a series of edits. this validates the
selection state.
In Keeping a Correct State it states that vertices belonging to edge are selected when edge selected. Similarly for edges, (and hence verts) of a face.
It does not mention the converse is true. Selecting verts selects their edges and / or faces. (Speculatively This works from the UI since it has a handle on "special edit mode mesh" ie select 4 verts in UI, vert select only, then on running script to check, face is selected)
To set a face to selected, makes sense to select the sub-elements. Work like an update method. Face sets edges, edges set verts. To conversely select a vert then check all its linked edges and faces, and set to selected would fire off our update reelecting the selected. Or similarly as a property getter checking all the selection of sub-elements, could prove expensive.
Instead select_flush
is used to sanitize state.
Akin to setting the context tool select mode calling bm.select_flush_mode()
will flush the states according to those set in bmesh.select_mode
.
Test scripts. both designed to select face and extrude even in select only vertex mode. context.tool_settings.mesh_select_mode = (True, False, False)
,
Selects verts, flushes mode, extrudes face.
import bpy
import bmesh
context = bpy.context
me = context.object.data
bmesh.select_mode = {'VERT', 'EDGE', 'FACE'}
bm = bmesh.from_edit_mesh(me)
for v in bm.verts:
v.select = v.co.z > 0
# flush the selection
bm.select_flush_mode()
bpy.ops.mesh.extrude_region_move(
TRANSFORM_OT_translate={"value" : (0, 0, 2)}
)
If we use faces can skip the flush call and select the faces based on the vert selection
for f in bm.faces:
f.select = all(v.select for v in f.verts)
but, IMO if you are going to extrude regions, generally only want faces, not edges or verts, so rather than diddle around with vertex selection, select faces instead (and vertex edge selection is done for us) The so called brute force approach
for f in bm.faces:
f.select = all(v.co.z > 0 for v in f.verts)
Test script.
import bpy
import bmesh
context = bpy.context
me = context.object.data
bm = bmesh.from_edit_mesh(me)
for f in bm.faces:
f.select = all(v.co.z > 0 for v in f.verts)
bpy.ops.mesh.extrude_region_move(
TRANSFORM_OT_translate={"value" : (0, 0, 2)})
As mentioned in prior answer, recommend using bmesh.ops
operators over bpy.ops.mesh..
. The geometry is passed to the operator, rather than manipulating context and selection.
Leave selection to the user, or a selection operator.
Can use the tag property
for v i bm.verts:
v.tag = some_long_winded_test_bool_func
for f in bm.faces:
f.select = all(v.tag for v in f.verts)
to avoid calculating per vert per face, and verts not part of a face.