Add vert on left mouse click
Further to this answer added code to add vertex on left mouse click. (Using method explained here) Added a list to class to hold the newly added vertices, as suggested via this question.
Things to note:
Vertex coordinates are local coordinates, whereas the calculated 3d cursor position is a global coordinate. To convert global to local the global vector is multiplied by the objects matrix world inverted.
A class property for the matrix world inverted, similar to setting cls.bm
for bmesh to avoid inverting the matrix each time.
When writing operators or panels, very rarely (if ever) do you need to access context via bpy.context
. If context
is an argument use it. I often use context = bpy.context
atop of test scripts as a convenient way to later copy / paste into code where context
is defined.
import bpy
import bmesh
from bpy_extras.view3d_utils import region_2d_to_location_3d
bmeshes = {}
class Modal(bpy.types.Operator):
bl_idname = "object.modal"
bl_label = "Modal Op"
bl_description = "Other thingy"
bl_options = {"REGISTER"}
bm = None
added_verts = []
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'MESH'
@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):
v = self.bm.verts.new(loc)
self.added_verts.append(v)
return v
def modal(self, context, event):
# no longer in edit mode
if context.mode != 'EDIT_MESH':
self.bm.free()
self.bm = None
return {'CANCELLED'}
ob = context.edit_object
me = ob.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":
x, y = event.mouse_region_x, event.mouse_region_y
region = context.region
rv3d = context.space_data.region_3d
loc = region_2d_to_location_3d(region, rv3d, (x, y), (0, 0, 0))
v = self.add_vert(ob.matrix_world.inverted() * loc)
v.select = True
if event.type in {"RIGHTMOUSE", "ESC"}:
self.bm.verts.index_update()
bmesh.update_edit_mesh(me)
print("added", self.added_verts)
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()
Btw. If you put minimal working code into your question it would be a lot easier to work out where your particular mistake is.