Apply Modifier for Object with Shape Keys Add-on update for 2.8x

Hey everyone,

I’m trying to update an add-on made by Przemysław Bągard and I’ve already update some of the code, but I’m getting an error when I try to use the add-on which I don’t know how to fix.

Traceback (most recent call last):
  File "/home/lucas/Desktop/Prêt-à-Template/01_3d/maternity_09.blend/ApplyModifierForObjectWithShapeKeys.py", line 89, in execute
AttributeError: bpy_struct: attribute "objects" from "ViewLayer" is read-only

location: <unknown location>:-1

Any help, please?

Here is what I got so far.

bl_info = {
    "name":         "Apply modifier for object with shape keys",
    "author":       "Przemysław Bągard",
    "blender":      (2,80,0),
    "version":      (0,1,1),
    "location":     "Context menu",
    "description":  "Apply modifier and remove from the stack for object with shape keys (Pushing 'Apply' button in 'Object modifiers' tab result in an error 'Modifier cannot be applied to a mesh with shape keys').",
    "category":     "Object Tools > Multi Shape Keys"
}

import bpy, math
from bpy.props import *

# Algorithm:
# - Duplicate active object as many times as the number of shape keys
# - For each copy remove all shape keys except one
# - Removing last shape does not change geometry data of object
# - Apply modifier for each copy
# - Join objects as shapes and restore shape keys names
# - Delete all duplicated object except one
# - Delete old object
# - Restore name of object and object data

def applyModifierForObjectWithShapeKeys(context, modifierName):
    list_names = []
    list = []
    list_shapes = []
    if context.object.data.shape_keys:
        list_shapes = [o for o in context.object.data.shape_keys.key_blocks]
    
    if(list_shapes == []):
        bpy.ops.object.modifier_apply(apply_as='DATA', modifier=modifierName)
        return context.view_layer.objects
    
    list.append(context.view_layer.objects)
    for i in range(1, len(list_shapes)):
        bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 0), "constraint_axis":(False, False, False), "constraint_orientation":'GLOBAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "texture_space":False, "release_confirm":False})
        list.append(context.view_layer.objects)

    for i, o in enumerate(list):
        context.scene.objects = o
        list_names.append(o.data.shape_keys.key_blocks[i].name)
        for j in range(i+1, len(list))[::-1]:
            context.object_shape_key_index = j
            bpy.ops.object.shape_key_remove()
        for j in range(0, i):
            context.object_shape_key_index = 0
            bpy.ops.object.shape_key_remove()
        # last deleted shape doesn't change object shape
        context.object_shape_key_index = 0
        bpy.ops.object.shape_key_remove()
        # time to apply modifiers
        bpy.ops.object.modifier_apply(apply_as='DATA', modifier=modifierName)
    
    bpy.ops.object.select_all(action='DESELECT')
    context.view_layer.objects = list[0]
    list[0].select = True
    bpy.ops.object.shape_key_add(from_mix=False)
    context.object.data.shape_keys.key_blocks[0].name = list_names[0]
    for i in range(1, len(list)):
        list[i].select = True
        bpy.ops.object.join_shapes()
        list[i].select = False
        context.object.data.shape_keys.key_blocks[i].name = list_names[i]
    
    bpy.ops.object.select_all(action='DESELECT')
    for o in list[1:]:
        o.select = True

    bpy.ops.object.delete(use_global=False)
    context.view_layer.objects = list[0]
    context.view_layer.objects.select = True
    return context.view_layer.objects

class ApplyModifierForObjectWithShapeKeysOperator(bpy.types.Operator):
    bl_idname = "object.apply_modifier_for_object_with_shape_keys"
    bl_label = "Apply Modifiers w/ Shape Keys"
 
    def item_list(self, context):
        return [(modifier.name, modifier.name, modifier.name) for modifier in bpy.context.view_layer.objects.active.modifiers]
 
    my_enum = EnumProperty(name="Modifier name",
        items = item_list)
 
    def execute(self, context):
    
        ob = context.view_layer.objects
        bpy.ops.object.select_all(action='DESELECT')
        context.view_layer.objects = ob
        context.view_layer.objects.selected = True
        applyModifierForObjectWithShapeKeys(context.window, self.my_enum)
        
        return {'FINISHED'}
 
    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)
        
        
class DialogPanel(bpy.types.Panel):
    bl_label = "Apply Modifiers w/ Shape Keys"
    bl_idname = "object.apply_modifier_for_object_with_shape_keys"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Edit"
 
    def draw(self, context):
        self.layout.operator("object.apply_modifier_for_object_with_shape_keys")
 
 
def menu_func(self, context):
    self.layout.operator("object.apply_modifier_for_object_with_shape_keys", 
        text="Apply Modifiers for Object with Shape Keys")
        
classes = ( ApplyModifierForObjectWithShapeKeysOperator, DialogPanel,)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)
            
def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
        
if __name__ == "__main__":
    register()   
    
   

The add-on is working now, feel free to try it.t

Download as zip and install like any other add-on.

1 Like