1
$\begingroup$

I've made a lot of scripts that had this error: ReferenceError: BMesh data of type BMesh has been removed. While I've usually found workarounds I would like to know what causes this error and how to fix it for future scripts.

Edit: This is my fence.

import bpy
import bmesh


class Create():
    mesh = bpy.context.active_object
    bm = bmesh.from_edit_mesh(mesh.data)

    def Verts(self,pose):
             self.bm.verts.ensure_lookup_table()
        self.bm.verts.new((1,1,1))
        bmesh.update_edit_mesh(self.mesh.data


class Modal(bpy.types.Operator):
    bl_idname = "object.modal"
    bl_label = "Modal Op"
    bl_description = "Other thingy"
    bl_options = {"REGISTER"}
    @classmethod
    def poll(cls, context):
        return True

    def invoke(self, context, event):
        bpy.ops.object.mode_set(mode='EDIT')
        context.window_manager.modal_handler_add(self)
        return {"RUNNING_MODAL"}

    def modal(self, context, event):
        c = Create()
        if event.type == "LEFTMOUSE" and event.value == "PRESS":
            c.Verts((0,0,1))
            print("Test")

        if event.type in {"RIGHTMOUSE", "ESC"}:

            return {"CANCELLED"}
        keys = ["WHEELUPMOUSE","WHEELDOWNMOUSE","MIDDLEMOUSE","LEFTMOUSE"]

        for i in keys:
            if event.type == i:
                return{"PASS_THROUGH"}

        return {"RUNNING_MODAL"}
def register():
    bpy.utils.register_class(Modal)

def unregister():
    bpy.utils.unregister_class(Modal)

if __name__ == "__main__":
    register()
$\endgroup$
5
  • $\begingroup$ Most commonly this is caused by making an edit mode bmesh.from_edit_mesh(me), and then toggling object mode. $\endgroup$
    – batFINGER
    Commented May 1, 2018 at 5:58
  • $\begingroup$ How can I avoid it? $\endgroup$
    – sajdnv
    Commented May 1, 2018 at 11:19
  • $\begingroup$ Don't toggle object / edit mode with an active live edit bmesh. Suggest posting some samples from your scripts demonstrating how you invoke the error. Otherwise it becomes a guessing game. Basic rule of thumb I use is if's not needed as a UI tool, use object mode bmesh. $\endgroup$
    – batFINGER
    Commented May 1, 2018 at 11:30
  • $\begingroup$ How and when do you want the operator active? If it's an edit mode tool suggest making switch to object mode cancel the operator. If context.mode != 'EDIT_MESH'. $\endgroup$
    – batFINGER
    Commented May 1, 2018 at 12:16
  • $\begingroup$ I would do that but I want to stay in edit mode when it’s cancelled. $\endgroup$
    – sajdnv
    Commented May 1, 2018 at 12:23

1 Answer 1

4
$\begingroup$

Assigning class properties

The error you were seeing was in the way you were setting the bmesh in your Create class. The property bm will be the bmesh for the context edit mesh when the sctipt was run, rather than, what you want, when the operator is invoked.

Suggest rather than instancing the class in modal loop, make one instance in invoke and use that. Add a constructor to your Create class with an argument context to ensure it is for the context mesh.

Example where the bm is set as a class property of the operator.

import bpy
import bmesh

bmeshes = {}

class Modal(bpy.types.Operator):
    bl_idname = "object.modal"
    bl_label = "Modal Op"
    bl_description = "Other thingy"
    bl_options = {"REGISTER"}

    bm = None

    @classmethod
    def poll(cls, context):
        return True

    @classmethod
    def bmesh(cls, context):
        me = context.edit_object.data
        cls.bm = bmesh.from_edit_mesh(me)

    def invoke(self, context, event):
        bpy.ops.object.mode_set(mode='EDIT')
        self.bmesh(context)
        context.window_manager.modal_handler_add(self)
        return {"RUNNING_MODAL"}

    def add_vert(self, loc):
         return self.bm.verts.new(loc)

    def modal(self, context, event):
        # no longer in edit mode
        if context.mode != 'EDIT_MESH':
            self.bm.free()
            self.bm = None
            return {'CANCELLED'}

        me = context.edit_object.data
        if self.bm is None or not self.bm.is_valid:
            # in edit mode so try make a new bmesh
            self.bmesh(context)            
        if event.type == "LEFTMOUSE" and event.value == "PRESS":
            v = self.add_vert((0, 0, 1))
            # update after all operations
            self.bm.verts.index_update()
            bmesh.update_edit_mesh(me)
            print("added", v)

        if event.type in {"RIGHTMOUSE", "ESC"}:
            return {"CANCELLED"}

        if event.type in ["WHEELUPMOUSE","WHEELDOWNMOUSE","MIDDLEMOUSE","LEFTMOUSE"]:
            return{"PASS_THROUGH"}

        return {"RUNNING_MODAL"}

def register():
    bpy.utils.register_class(Modal)

def unregister():
    bpy.utils.unregister_class(Modal)

if __name__ == "__main__":
    register()

For panel code to have an edit mode bmesh I often use a global dictionary

bm = bmeshes.setdefault(me.name, bmesh.from_edit_mesh(me))

which can be set / cleared using the panels' poll method.

$\endgroup$

You must log in to answer this question.

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