1

I'm having a problem updating a mesh after initial creation. I like to create a mesh in one step and update it's vertices afterwards, without completely recreating the mesh.

After several iterations I trimmed the code down to a minimum (below) and it doesn't seem to work... I'm setting a custom property ("update") to the active object and print "create", if the "update" property exists I print "update". The code does not seem to take the update-branch and the property does not seem to be set. If I de-select the object and execute the Operator again, the property is set.

What am I missing? Do I need to update the object? Is there another way of doing this?

def execute(self, context):
    print(context.active_object.data.keys())

    currentObject = context.active_object

    if ('mesh_update' in currentObject.data.keys()):
        print("update")
    else:
        currentObject.data["update"] = True
        print("create")

    return {'FINISHED'}

Additional information

The operator is called from "add object" menu (the one using shift + a). I also tried an operator property, a group property for objects in general and some other possibilities for days now. The operator property does not work because this setting has to be object (or mesh?) specific and this setting would be carried to the next object the operator gets applied to. Pre defined object properties have the same effect as the dynamic one in the example code above.

Update #1

I handled my problem in a different way now by using a local variable inside the operator to switch between the "create" and "update" stages. This eliminates some other issues and is easier to work with. I had my code working this way some iterations ago while searching for a solution. This leads to maybe the base problem I am trying so solve here: my active object changes between those stages! I explicitly set my newly created object to be the active one but as soon as hitting FINISHED and the operator's execute method starting over again (with the new stage "update"!) the active object changes.

updateMesh = False

def execute(self, context): use_enter_edit_mode = context.preferences.edit.use_enter_edit_mode context.preferences.edit.use_enter_edit_mode = False

    if context.mode == "EDIT_MESH":
        bpy.ops.object.mode_set(mode='OBJECT')

    currentObject = context.active_object
    # THE "OLD"/INITIALLY ACTIVE OBJECT IS PRINTED HERE ON THE VERY FIRST RUN
    print(currentObject)

    if self.updateMesh == True:
        # ERROR
        # THE "OLD"/INITIALLY ACTIVE OBJECT IS PRINTED HERE
        # NOT THE NEW ONE FROM BELOW
        print("update " + currentObject.name)
    else:
        self.updateMesh = True
        # A NEW OBJECT IS CREATED HERE, LINKED TO VIEW LAYER
        # AND SET AS ACTIVE VIEW LAYER OBJECT
        # OUTPUTS THE NEW OBJECT
        print("create " + currentObject.name)

    if use_enter_edit_mode:
        bpy.ops.object.mode_set(mode = 'EDIT')
    # restore pre operator state
    context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode

    return {'FINISHED'}

Update #2

Here is a complete working example. Setup is like this:

  1. execute the script below
  2. Window > Toggle System Console
  3. create an object (Monkey/Suzanne for example)
  4. while object selected press SHIFT + A
  5. select Mesh > Object Update Test (car icon...)
  6. edit parameter (Dummy Property)

What it does:

  • Suzanne is the active object
  • an object "NewObject" is created and set active
  • changing the property "Dummy Property" removes "NewObject" and sets Suzanne active again

What it SHOULD do:

  • keep the object and show "update NewObject" when changing the property
import bpy
import bmesh

from bpy.utils import ( register_class, unregister_class ) from bpy.props import ( BoolProperty, FloatProperty ) from bpy.types import Operator from mathutils import Vector

class ObjectUpdateOperator(Operator): bl_idname = "mesh.objectupdatetest" bl_label = "Object Update Test" bl_options = {'REGISTER', 'UNDO'} #, 'PRESET'}

dummyProp : FloatProperty(
    name = "Dummy Property",
    default = 0.2,
    min = 0.0001,
    max = 10000.0,
    precision = 4,
    step = 4,
    )

def draw(self, context):
    layout = self.layout
    box = layout.box()
    box.label(text="Basic Parameters")
    box.prop(self, 'dummyProp')

@classmethod
def poll(cls, context):
    return context.scene is not None

def invoke(self, context, event):
    self.execute(context)
    return {'FINISHED'}

updateMesh = False

def execute(self, context):
    use_enter_edit_mode = context.preferences.edit.use_enter_edit_mode
    context.preferences.edit.use_enter_edit_mode = False

    if context.mode == "EDIT_MESH":
        bpy.ops.object.mode_set(mode='OBJECT')

    currentObject = context.active_object

    # problematic part...
    if self.updateMesh == True: # update object/mesh
        print("update " + currentObject.name)

    else: # create object/mesh
        print("create")
        print("active object: " + currentObject.name)
        new_mesh = bpy.data.meshes.new("NewMesh")
        new_verts = [
            Vector((-1, 1, 0)),
            Vector((1, 1, 0)),
            Vector((1, -1, 0)),
            Vector((-1, -1, 0)),
        ]

        new_faces = [[0, 1, 2, 3]]
        new_mesh.from_pydata(new_verts, [], new_faces)
        new_object = bpy.data.objects.new(name="NewObject", object_data=new_mesh)
        view_layer = context.view_layer
        view_layer.active_layer_collection.collection.objects.link(new_object)
        view_layer.objects.active = None
        new_object.select_set(True)
        view_layer.objects.active = new_object
        print("NEW active object: " + context.active_object.name)
        self.updateMesh = True


    if use_enter_edit_mode:
        bpy.ops.object.mode_set(mode = 'EDIT')
    # restore pre operator state
    context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode

    return {'FINISHED'}


def menu_item(self, context): # we need at minimum one object selected! if len(context.selected_objects) == 0: return

layout = self.layout
layout.operator("mesh.objectupdatetest", text="Object Update Test", icon="AUTO")


register and unregister

classes = ( ObjectUpdateOperator, )

def register(): for cls in classes: register_class(cls)
# add menu to shift-a add object menu bpy.types.VIEW3D_MT_mesh_add.append(menu_item)

def unregister(): for cls in reversed(classes): unregister_class(cls)
# remove menu item bpy.types.VIEW3D_MT_mesh_add.remove(menu_item)

if name == "main": register() ```

48DESIGN
  • 11
  • 2
  • A parametric approach is good ol' chestnut. Once a primitive is created only the name is an indicator of origins. (if not changed as well) Possible dupe https://blender.stackexchange.com/questions/101141/parametric-primitives-through-python-script ?? – batFINGER Feb 16 '21 at 13:57
  • Thanks for looking into this. I think the problem is more fundamental. Something seems to block the properties from updating if I set them by code. If I set a property of an object it even shows up correctly inside the "Item" panel under "Properties" but if I try to access this property it seems like it has not been set! If I deselect the object and run the code/operator again the property gets recognized. – 48DESIGN Feb 16 '21 at 14:30
  • IMO issue commented is same as here https://blender.stackexchange.com/questions/181649/replicate-value-stored-in-object-into-properties-of-new-one The execute is undoing redoing as settings are changing. – batFINGER Feb 16 '21 at 14:34
  • Thank you, batFINGER, for those suggestions. Maybe I only don't understand what is done in those posts but I didn't get my problem fixed. – 48DESIGN Feb 17 '21 at 10:54
  • @batFINGER I've updated me description and code above. Please see the code comments. – 48DESIGN Feb 17 '21 at 11:08
  • @batFINGER I've added a working example to copy&paste in combination with a detailed description. There must be something I don't understand about how blender is handling things... – 48DESIGN Feb 17 '21 at 20:39
  • I have absolutely no clue what I am missing... either it is a bug in Blender or I don't understand the whole mechanism of Blender (and python?). – 48DESIGN Feb 19 '21 at 14:04
  • No it's not a bug in blender it's how blender operators work.. As a little test hit G and move the cube, in rotation properties change a setting, then in the Move operators redo panel change an operator property, the rotation will be reverted to what it was. ie the state when blender was invoked. IMO you are going to go around in a circle trying to change this behaviour. – batFINGER Feb 19 '21 at 15:19
  • Ok, thanks for clarification. So there is no workaround for this? – 48DESIGN Feb 19 '21 at 15:54
  • I did some more research to find a solution to my initial problem. Could either "shape keys" or "drivers" change the mesh (vertices) after creating in an "update branch" of the operator? Or maybe even changing the operator of the created object? – 48DESIGN Feb 21 '21 at 09:57

0 Answers0