I've asked this question but couldn't get any answer, so I decided I'll post it again, trying to be more specific.
Let’s assume I have an active object in the scene. The object itself is just a couple of vertical faces but it has a solidify modifier, a hook modifier attached to some of its vertices and a boolean modifier (subtracting part of it with another object). It looks like this:
The script is supposed to:
- Make a copy of selected object with its modifiers
- In that copy apply some modifiers and remove others
- Remove most of the object leaving only some edges (namely the lower ones) and extrude them
- Name the modified copy
The script looks like this:
import bpy
import bmesh
from mathutils import Vector
context = bpy.context
ob = context.object
src_verts =[]
bottom_verts =[]
ext_edges =[]
for obj in [o for o in bpy.context.scene.objects if o.type == 'MESH' and o.name == ob.name + ' kondygnacje_podziemne']:
bpy.data.objects.remove(obj, do_unlink=True)
count_ob = float(len(ob.data.vertices))
center_ob = (1.0 / count_ob) * sum([v.co for v in ob.data.vertices], Vector())
#getting lower vertices of object:
for v in [v for v in ob.data.vertices if v.co[2] < center_ob[2]]:
src_verts.append(v.index)
#make a copy of object to alter it after applying and removing certain modifiers:
podz = ob.copy()
podz.data = ob.data.copy()
bpy.context.scene.collection.objects.link(podz)
ob.select_set(False)
context.view_layer.objects.active = podz
#before creating bmesh, apply existing hook and solidify modifiers and remove boolean modifiers:
for mod in [m for m in podz.modifiers if m.type == 'HOOK']:
#print(podz.name)
bpy.ops.object.modifier_apply( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'BOOLEAN']:
bpy.ops.object.modifier_remove( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'SOLIDIFY']:
bpy.ops.object.modifier_apply( modifier = mod.name )
#create bmesh from 'podz' after removing/applying modifiers:
bm_podz = bmesh.new()
dg = context.evaluated_depsgraph_get()
bm_podz.from_object(podz, dg)
#make a list of verts to delete
wyk=[]
for v in [v for v in bm_podz.verts if v.index not in src_verts]:
wyk.append(v)
bmesh.ops.delete(bm_podz, geom = wyk, context = 'VERTS')
# get the remaining edges to extrude:
bm_podz.edges.ensure_lookup_table()
for e in bm_podz.edges:
ext_edges.append(e)
#extrude edges:
added_e = bmesh.ops.extrude_edge_only(bm_podz, edges = ext_edges)
print(len([e for e in bm_podz.edges if isinstance(e, bmesh.types.BMEdge)]))
extruded = [v for v in added_e['geom'] if isinstance(v, bmesh.types.BMVert)]
# move extruded vertices to desired position:
bmesh.ops.translate(bm_podz, verts=extruded, vec=(0.0, 0.0,-3.0))
#update mesh:
bm_podz.to_mesh(podz.data)
name = ob.name + 'spam'
podz.name = name
bm_podz.free()
del src_verts
del ext_edges
del bottom_verts
del wyk
when it is run from blender text editor it works as intended, creating this (a "belt" along lower edges of object): however when I use exactly the same script as a function in addon (to simplify here I paste a simple "addon" with just that one function triggered with boolean switch in object properties panel):
import bpy
import bmesh
from mathutils import Vector
def cz_podz(self, context):
context = bpy.context
ob = context.object
src_verts =[]
bottom_verts =[]
ext_edges =[]
for obj in [o for o in bpy.context.scene.objects if o.type == 'MESH' and o.name == ob.name + ' kondygnacje_podziemne']:
bpy.data.objects.remove(obj, do_unlink=True)
count_ob = float(len(ob.data.vertices))
center_ob = (1.0 / count_ob) * sum([v.co for v in ob.data.vertices], Vector())
#getting lower vertices of object:
for v in [v for v in ob.data.vertices if v.co[2] < center_ob[2]]:
src_verts.append(v.index)
#make a copy of object to alter it after applying and removing certain modifiers:
podz = ob.copy()
podz.data = ob.data.copy()
bpy.context.scene.collection.objects.link(podz)
ob.select_set(False)
context.view_layer.objects.active = podz
#before creating bmesh, apply existing hook and solidify modifiers and remove boolean modifiers:
for mod in [m for m in podz.modifiers if m.type == 'HOOK']:
#print(podz.name)
bpy.ops.object.modifier_apply( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'BOOLEAN']:
bpy.ops.object.modifier_remove( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'SOLIDIFY']:
bpy.ops.object.modifier_apply( modifier = mod.name )
#create bmesh from 'podz' after removing/applying modifiers:
bm_podz = bmesh.new()
dg = context.evaluated_depsgraph_get()
bm_podz.from_object(podz, dg)
#make a list of verts to delete
wyk=[]
for v in [v for v in bm_podz.verts if v.index not in src_verts]:
wyk.append(v)
bmesh.ops.delete(bm_podz, geom = wyk, context = 'VERTS')
# get the remaining edges to extrude:
bm_podz.edges.ensure_lookup_table()
for e in bm_podz.edges:
ext_edges.append(e)
#extrude edges:
added_e = bmesh.ops.extrude_edge_only(bm_podz, edges = ext_edges)
print(len([e for e in bm_podz.edges if isinstance(e, bmesh.types.BMEdge)]))
extruded = [v for v in added_e['geom'] if isinstance(v, bmesh.types.BMVert)]
# move extruded vertices to desired position:
bmesh.ops.translate(bm_podz, verts=extruded, vec=(0.0, 0.0,-3.0))
#update mesh:
bm_podz.to_mesh(podz.data)
name = ob.name + 'spam'
podz.name = name
bm_podz.free()
del src_verts
del ext_edges
del bottom_verts
del wyk
bpy.types.Object.myBool4 = bpy.props.BoolProperty(name="boolean_switch", default=False, update=cz_podz)
class ParametryZab_Panel(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "Spam"
bl_idname = "OBJECT_PT_"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
def draw(self, context):
layout = self.layout
scene = context.scene
obj = context.object
row = layout.row()
row.prop(obj, "myBool4", toggle = True)
def register():
bpy.utils.register_class(ParametryZab_Panel)
def unregister():
bpy.utils.unregister_class(ParametryZab_Panel)
if __name__ == "__main__":
register()
the result is entirely different:
It seems like when the script is run from the "addon", it applies/removes modifiers of the original object, not its copy, while when running standalone from text editor it works ok. It's possibly something embarrassingly obvious but I have no idea why that happens.
I'd appreciate if someone could explain that.
Thank You.
ob.
. (the source object) despitecontext.view_layer.objects.active = podz
. But I don't understand why. $\endgroup$