I have a script that currently fetches the mesh of a selected object, modifies it, and then updates the original mesh with the modified mesh. I’d like to change this so that the user can apply the change to a particular shape key of the mesh. Is there a way to do this?
for obj in ctx.selected_objects:
if obj.type == 'MESH':
mesh = obj.data
#calculate new normals
mesh.normals_split_custom_set(normals)
1 Like
Edit: Oh you want shape-key data… nvm.
I would suggest using one of the native operator functions bpy.ops.object.make_links_data
:
Code
import bpy
MISC_SELECTED_OBJ = "Icosphere"
LAST_SELECTED_OBJ = "Cube"
bpy.data.objects[str(MISC_SELECTED_OBJ)].select_set(True)
bpy.data.objects[str(LAST_SELECTED_OBJ)].select_set(True)
bpy.ops.object.make_links_data(type="OBDATA")
Non-Code
CTRL + L → Link Object Data
After doing some digging, it looks like I can access the shape key data via obj.active_shape_key.data
which is a list of ShapeKeyPoint structs. However, these appear to only hold positional data, so it looks like I cannot set normal data there. If this is not the case, please let me know.
I think I got the, “copy shape keys,” code to work finally.
Apparently Blender already has a handy dandy operator function for it already:
import bpy
# OBJECT VARIABLES
obj_original = bpy.data.objects["Original"]
obj_new = bpy.data.objects["New"]
# OBJECT SELECTIONS
bpy.ops.object.select_all(action="DESELECT")
obj_new.select_set(True)
obj_original.select_set(True)
bpy.context.view_layer.objects.active = obj_original
# SHAPE KEYS
obj_original.shape_key_clear()
bpy.ops.object.shape_key_transfer()
obj_original.show_only_shape_key = False
When you run the script it should override all shape keys on your last selected, active object.
Thanks. I was looking more for a way to manipulate the shape key data directly (and normals in particular), but these methods could be useful.
While the below example is for creating a shape key setting the vertex positions it may be of assistance for you:
- edit: modified code to include changing existing shape_key if named key exists.
import bpy
import random
from mathutils import Vector
def mod_obj(obj, sk=None):
if obj.type != 'MESH':
return {'CANCELLED'}
old_mode = bpy.context.mode
if bpy.context.mode != 'OBJECT':
bpy.ops.object.mode_set(mode = 'OBJECT')
obj_verts = obj.data.vertices
sk_verts = []
for vert in obj_verts:
scl = .5
rand_x = random.uniform(-1, 1) * scl
rand_y = random.uniform(-1, 1) * scl
rand_z = random.uniform(-1, 1) * scl
new_pos = vert.co + Vector((rand_x, rand_y, rand_z))
sk_verts.append(new_pos)
if not obj.data.shape_keys:
obj.shape_key_add(name='Basis')
if not sk:
sk = obj.shape_key_add()
for i in range(len(obj_verts)):
sk.data[i].co = sk_verts[i]
if old_mode != 'OBJECT':
bpy.ops.object.mode_set(mode = old_mode)
obj = bpy.context.object
key_name = "Key"
if obj.data.shape_keys:
sk = obj.data.shape_keys.key_blocks.get(key_name)
else:
sk = None
mod_obj(obj, sk)
2 Likes