2
$\begingroup$

I've been struggling with a bmesh problem for a while now and I can't wrap my head around it. When I free my bmesh data and try to make a new bm instance with the same object, it points to the old freed data.

Simplified code snippet:

import bpy
import bmesh

obj = bpy.data.objects["Cube"]

me = obj.data
bm = bmesh.from_edit_mesh(me) #creates new bm
verts = bm.verts
for vert in verts:
    vert.co[2] += 1
bmesh.update_edit_mesh(obj.data)
bm.free()

me = obj.data
bm = bmesh.from_edit_mesh(me) #points to old dead bm (memory pointer is the same)
verts = bm.verts
for vert in verts:
    vert.co[2] -= 1
bmesh.update_edit_mesh(obj.data)
bm.free()

One thing that does work is switching the mode twice like this:

import bpy
import bmesh

obj = bpy.data.objects["Cube"]

me = obj.data
bm = bmesh.from_edit_mesh(me) #creates new bm
verts = bm.verts
for vert in verts:
    vert.co[2] += 1
bmesh.update_edit_mesh(obj.data)
bm.free() 

bpy.ops.object.editmode_toggle()
bpy.ops.object.editmode_toggle()

me = obj.data
bm = bmesh.from_edit_mesh(me) #creates new bm
verts = bm.verts
for vert in verts:
    vert.co[2] -= 1
bmesh.update_edit_mesh(obj.data)
bm.free()

This is however something I really don't want to do because it's just ugly and it shouldn't be necessary.

Running the second script twice will crash unless you switch mode twice before running it again.

Turning just this part into an operator will also crash if you run it twice without switching modes twice between executions.

obj = bpy.data.objects["Cube"]

me = obj.data
bm = bmesh.from_edit_mesh(me) #creates new bm
verts = bm.verts
for vert in verts:
    vert.co[2] += 1
bmesh.update_edit_mesh(obj.data)
bm.free()

How can I avoid this problem in a nicer way? I don't want people using my add-on to have to switch mode twice if they want to execute the same operator twice. But I also would like to not switch modes constantly in my code

$\endgroup$
  • $\begingroup$ Probably, bm = bmesh.new() then bm.from_mesh( obj.data ) will work avoiding the edit mode problem. You can then bm.free() and get a new bm = bmesh.new() for the next obj $\endgroup$ – lemon Aug 23 '19 at 10:58
  • $\begingroup$ Problem is, I need to do this in edit mode. and if I use bm = bmesh.new() then bm.from_mesh(obj.data) before I free my bm data, then I am freeing the wrong data and the chance for memory leaks increases. (I'm working on a massive add-on where performance is quite important) $\endgroup$ – Singulasar Aug 23 '19 at 11:11
  • $\begingroup$ What I don't get is why editing/modifying the same object multiple times in the same edit mode session? $\endgroup$ – lemon Aug 23 '19 at 11:21
  • $\begingroup$ The addon has a lot of operators. some of these operators are usually executed one after another without leaving edit mode (some need some selected verts as input). $\endgroup$ – Singulasar Aug 23 '19 at 11:26
  • 1
    $\begingroup$ Getting rid of the free does solve the problem @lemon I will leave it like this unless someone comes up with something better. It does feel like strange behaviour that a new instance can't be made after freeing. I am pretty paranoid of sentences like "it's hard to predict when this will be" I noticed that if I don't free the data it keeps pointing to the same memory location. So it does keep the bmesh in memory until I leave edit mode. I was hoping I could avoid this since I'm working on high poly meshes But thank you, it did solve my problem and I learned some more about inner workings $\endgroup$ – Singulasar Aug 23 '19 at 12:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.