Skip to content

Instantly share code, notes, and snippets.

@matty
Last active October 9, 2023 02:27
Show Gist options
  • Save matty/7942fc4d0b5c4346f6f4a129167257f5 to your computer and use it in GitHub Desktop.
Save matty/7942fc4d0b5c4346f6f4a129167257f5 to your computer and use it in GitHub Desktop.
Remove non-driven shape keys for Blender 3+
bl_info = {
"name": "Remove Non-driven Shape Keys",
"description": "Removes any Shape Key which doesn't affect any vertices within tolerance.",
"version": (1, 0),
"blender": (3, 0, 0),
"category": "Object",
}
import bpy
import numpy as np
def main_function(self, context):
# Tolerance to small differences, change it if you want
tolerance = 0.001
assert bpy.context.mode == 'OBJECT', "Must be in object mode!"
for ob in bpy.context.selected_objects:
if ob.type != 'MESH': continue
if not ob.data.shape_keys: continue
if not ob.data.shape_keys.use_relative: continue
kbs = ob.data.shape_keys.key_blocks
nverts = len(ob.data.vertices)
to_delete = []
# Cache locs for rel keys since many keys have the same rel key
cache = {}
locs = np.empty(3*nverts, dtype=np.float32)
for kb in kbs:
if kb == kb.relative_key: continue
kb.data.foreach_get("co", locs)
if kb.relative_key.name not in cache:
rel_locs = np.empty(3*nverts, dtype=np.float32)
kb.relative_key.data.foreach_get("co", rel_locs)
cache[kb.relative_key.name] = rel_locs
rel_locs = cache[kb.relative_key.name]
locs -= rel_locs
if (np.abs(locs) < tolerance).all():
to_delete.append(kb.name)
for kb_name in to_delete:
ob.shape_key_remove(ob.data.shape_keys.key_blocks[kb_name])
def draw_func(self, context):
layout = self.layout
obj = context.active_object
row = layout.row()
row.operator("object.remove_nondriven_shapekeys", text="Remove non-driven Shape Keys")
def register():
bpy.types.DATA_PT_shape_keys.append(draw_func)
bpy.utils.register_class(RemoveNonDrivenShapeKeysOperator)
def unregister():
bpy.types.DATA_PT_shape_keys.remove(draw_func)
bpy.utils.unregister_class(RemoveNonDrivenShapeKeysOperator)
class RemoveNonDrivenShapeKeysOperator(bpy.types.Operator):
bl_idname = "object.remove_nondriven_shapekeys"
bl_label = "Remove non-driven Shape Keys"
def execute(self, context):
main_function(self, context)
return {'FINISHED'}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment