I have the below addon installed in Blender 3.3. I get AttributeError:'Mesh' object has no attribute 'subdiv_prop' on line 137 when I click the 'Project Image' button. How do I resolve this?
bl_info = {
"name": "Tools",
"description": "Tools",
"author": "Tools",
"version": (1, 0, 1),
"blender": (3, 3, 0),
"location": "View3D > 'N' Panel > PRT",
"warning": "",
"wiki_url": "",
"doc_url": "",
"tracker_url": "",
"category": "3D View"
}
############### IMPORTS
import bpy
from bpy.utils import previews
import os
import math
from bpy.props import *
import bmesh
############### USER PANEL
class SNA_PT_Create_a_Product_Render(bpy.types.Panel):
bl_label = "Create a Product Render"
bl_idname = "SNA_PT_Create_a_Product_Render"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = 'PRT'
bl_order = 0
@classmethod
def poll(cls, context):
return True
def draw_header(self, context):
try:
layout = self.layout
except Exception as exc:
print(str(exc) + " | Error in Create a Product Promo panel header")
def draw(self, context):
try:
layout = self.layout
scene = context.scene
obj = context.object
box = layout.box()
box.enabled = True
box.alert = False
box.scale_x = 1.0
box.scale_y = 1.0
box.label(text=r"IMPORT ASSETS FROM OTHER FILES",icon= 'MESH_MONKEY')
row = box.row(align=True)
row.enabled = True
row.alert = False
row.scale_x = 1.0
row.scale_y = 1.0
op = row.operator("sna.append_model",text=r"Append Model",emboss=True,depress=False,icon_value=0)
op = row.operator("sna.link_model",text=r"Link Model",emboss=True,depress=False,icon_value=0)
row = box.row(align=True)
row.enabled = True
row.alert = False
row.scale_x = 1.0
row.scale_y = 1.0
op = row.operator("sna.import_fbx",text=r"Import FBX",emboss=True,depress=False,icon_value=0)
op = row.operator("sna.import_obj",text=r"Import OBJ",emboss=True,depress=False,icon_value=0)
box = layout.box()
box.enabled = True
box.alert = False
box.scale_x = 1.0
box.scale_y = 1.0
box.label(text=r"ADD DECAL / LABEL",icon= 'FILE_IMAGE')
row = box.row(align=True)
row.enabled = True
row.alert = False
row.scale_x = 1.0
row.scale_y = 1.0
op = row.operator("sna.import_image",text=r"Import Image",emboss=True,depress=False,icon_value=0)
row = layout.column()
row.alert = False if scene.shrink_target else True
box.label(text=r"Project Image to a Mesh")
op = box.prop(scene, "shrink_target")
row = layout.column()
op = box.operator(SNA_OT_Projector_Operator.bl_idname)
box = layout.box()
box.enabled = True
box.alert = False
box.scale_x = 1.0
box.scale_y = 1.0
box.label(text=r"MORE TOOLS",icon= 'TOOL_SETTINGS')
row = box.row(align=True)
row.prop(bpy.context.active_object,'is_shadow_catcher',icon_value=0,text=r"Turn Selected Object Into A Shadow Catcher",emboss=True,toggle=False,invert_checkbox=False,)
box = layout.box()
box.enabled = True
box.alert = False
box.scale_x = 1.0
box.scale_y = 1.0
box.label(text=r"RENDER YOUR PRODUCT",icon= 'RESTRICT_RENDER_OFF')
op = box.operator("sna.render_image",text=r"Render Image",emboss=True,depress=False,icon_value=0)
op = box.operator("sna.render_animation",text=r"Render Animation",emboss=True,depress=False,icon_value=0)
box = layout.box()
box.enabled = True
box.alert = True
box.scale_x = 1.0
box.scale_y = 1.0
box.label(text=r"NEED MORE TOOLS FOR YOUR PROJECTS?",icon= 'SHADERFX')
row = box.row(align=True)
row.operator("wm.url_open", text="See More Addons").url = ""
row.operator("wm.url_open", text="Request A Tool").url = ""
except Exception as exc:
print(str(exc) + " | Error in Create a Product Promo panel")
############### OPERATORS
class SNA_OT_Projector_Operator(bpy.types.Operator):
"""Project Image onto Mesh"""
bl_idname = "mesh.custom_subdiv"
bl_label = "Project Image"
bl_options = {'REGISTER', 'UNDO'}
subd_levels: IntProperty(default=30, options={'HIDDEN', 'SKIP_SAVE'})
@classmethod
def poll(cls, context):
return context.scene.shrink_target != context.active_object and context.active_object.type=='MESH' and context.mode=='OBJECT'
def execute(self, context):
obj = context.object
ob = context.object
me = ob.data
if me.subdiv_prop >= self.subd_levels:
self.report({'INFO'}, "Maximum reached")
return {'CANCELLED'}
else:
shrink_mod = None
for m in obj.modifiers:
if m.type == 'SHRINKWRAP':
shrink_mod = m
if shrink_mod is None:
shrink_mod = obj.modifiers.new(name="Projector", type='SHRINKWRAP')
shrink_mod.offset = 0.01
shrink_mod.target = context.scene.shrink_target
if shrink_mod.target is None:
self.report({"ERROR"},"Select a Target object above then click 'Project Image' button again")
return {'CANCELLED'}
bm = bmesh.new()
bm.from_mesh(me)
bmesh.ops.subdivide_edges(bm, edges=bm.edges, cuts=self.subd_levels, use_grid_fill=True)
bm.to_mesh(me)
me.update()
self.report({'INFO'}, "{} levels applied".format(self.subd_levels))
me.subdiv_prop =+ self.subd_levels
return {'FINISHED'}
class SNA_OT_Append_Model(bpy.types.Operator):
bl_idname = "sna.append_model"
bl_label = "Append model"
bl_description = "Import a model from another .blend file"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.ops.wm.append('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',)
except Exception as exc:
print(str(exc) + " | Error in execute function of Append model")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of Append model")
return self.execute(context)
class SNA_OT_Link_Model(bpy.types.Operator):
bl_idname = "sna.link_model"
bl_label = "Link model"
bl_description = "Link a model from another .blend file"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.ops.wm.link('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',)
except Exception as exc:
print(str(exc) + " | Error in execute function of New Operator")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of New Operator")
return self.execute(context)
class SNA_OT_Import_Fbx(bpy.types.Operator):
bl_idname = "sna.import_fbx"
bl_label = "Import FBX"
bl_description = "Import a model from a .FBX project file"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.ops.import_scene.fbx('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',)
except Exception as exc:
print(str(exc) + " | Error in execute function of New Operator")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of New Operator")
return self.execute(context)
class SNA_OT_Import_Obj(bpy.types.Operator):
bl_idname = "sna.import_obj"
bl_label = "Import OBJ"
bl_description = "Import a model from a .OBJ project file"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.ops.import_scene.obj('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',)
except Exception as exc:
print(str(exc) + " | Error in execute function of New Operator")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of New Operator")
return self.execute(context)
class SNA_OT_Render_Image(bpy.types.Operator):
bl_idname = "sna.render_image"
bl_label = "Render image"
bl_description = "Render your promo"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.ops.render.render('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',animation=False,write_still=False,use_viewport=True,layer=r"",scene=r"",)
except Exception as exc:
print(str(exc) + " | Error in execute function of Render image")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of Render image")
return self.execute(context)
class SNA_OT_Render_Animation(bpy.types.Operator):
bl_idname = "sna.render_animation"
bl_label = "Render animation"
bl_description = ""
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.ops.render.render('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',write_still=False,use_viewport=True,layer=r"",scene=r"",)
except Exception as exc:
print(str(exc) + " | Error in execute function of Render animation")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of Render animation")
return self.execute(context)
class SNA_OT_Import_Image(bpy.types.Operator):
bl_idname = "sna.import_image"
bl_label = "Import image"
bl_description = "Import your label / decal / sticker"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def invoke(self, context, event):
try:
bpy.ops.preferences.addon_enable('INVOKE_DEFAULT' if False else 'EXEC_DEFAULT',module=r"io_import_images_as_planes",)
except Exception as exc:
print(str(exc) + " | Error in invoke function of New Operator")
return self.execute(context)
def execute(self, context):
try:
bpy.ops.import_image.to_plane('INVOKE_DEFAULT' if True else 'EXEC_DEFAULT',)
except Exception as exc:
print(str(exc) + " | Error in execute function of New Operator")
return {"FINISHED"}
class SNA_OT_Shadow_Catcher(bpy.types.Operator):
bl_idname = "sna.shadow_catcher"
bl_label = "Shadow Catcher"
bl_description = ""
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
try:
bpy.context.active_object.is_shadow_catcher = True
except Exception as exc:
print(str(exc) + " | Error in execute function of Shadow Catcher")
return {"FINISHED"}
def invoke(self, context, event):
try:
pass
except Exception as exc:
print(str(exc) + " | Error in invoke function of Shadow Catcher")
return self.execute(context)
def target_poll(self, object):
return object.type == 'MESH'
############### REGISTER AND UNREGISTER ADDON
def register():
bpy.utils.register_class(SNA_PT_Create_a_Product_Render)
bpy.utils.register_class(SNA_OT_Append_Model)
bpy.utils.register_class(SNA_OT_Link_Model)
bpy.utils.register_class(SNA_OT_Import_Fbx)
bpy.utils.register_class(SNA_OT_Import_Obj)
bpy.utils.register_class(SNA_OT_Render_Image)
bpy.utils.register_class(SNA_OT_Render_Animation)
bpy.utils.register_class(SNA_OT_Import_Image)
bpy.utils.register_class(SNA_OT_Shadow_Catcher)
bpy.utils.register_class(SNA_OT_Projector_Operator)
bpy.types.Scene.shrink_target = bpy.props.PointerProperty(
name="Select Mesh",
type=bpy.types.Object,
poll=target_poll
)
def unregister():
bpy.utils.unregister_class(SNA_OT_Shadow_Catcher)
bpy.utils.unregister_class(SNA_OT_Import_Image)
bpy.utils.unregister_class(SNA_OT_Render_Animation)
bpy.utils.unregister_class(SNA_OT_Render_Image)
bpy.utils.unregister_class(SNA_OT_Import_Obj)
bpy.utils.unregister_class(SNA_OT_Import_Fbx)
bpy.utils.unregister_class(SNA_OT_Link_Model)
bpy.utils.unregister_class(SNA_OT_Append_Model)
bpy.utils.unregister_class(SNA_PT_Create_a_Product_Render)
bpy.utils.unregister_class(SNA_OT_Projector_Operator)
del bpy.types.Scene.shrink_target


subdiv_propis a custom property, which is not declared now in the addon. See theregisterandunregisterfunctions of the related topic. – Sietse Brouwer Sep 30 '22 at 09:17