Skip to content

Instantly share code, notes, and snippets.

@undefined9071
Last active October 23, 2024 06:54
Show Gist options
  • Save undefined9071/f598991e4457dd93d8ff6ea8bd2167b8 to your computer and use it in GitHub Desktop.
Save undefined9071/f598991e4457dd93d8ff6ea8bd2167b8 to your computer and use it in GitHub Desktop.
import bpy
import re
def get_shapekey(object_name, shape_name):
bpy.context.view_layer.objects.active = bpy.data.objects[object_name]
if bpy.context.object.data.shape_keys == None:
return None
for shape_key in bpy.context.object.data.shape_keys.key_blocks:
if shape_key.name == shape_name:
return shape_key
def reset_pose(root_object):
bpy.context.view_layer.objects.active = root_object
bpy.ops.object.posemode_toggle()
bpy.ops.pose.select_all(action='SELECT')
bpy.ops.pose.transforms_clear()
bpy.ops.object.posemode_toggle()
root = bpy.context.active_object
face_obj = bpy.data.objects["Face"]
if not re.search(r'(Avatar|Player|Art|Rig)', root.name) or root.type != 'ARMATURE':
raise BaseException("Avatar/Player/Art/*Rig Armature is not selected.")
use_bone_layer = False
bone_layer1_is_visible = False
if re.search(r'Rig', root.name):
if bpy.app.version >= (4, 0, 0) and len(root.data.collections) > 0:
use_bone_layer = True
bone_layer1_is_visible = root.data.collections[0].is_visible
root.data.collections[0].is_visible = True
if bpy.app.version < (4, 0, 0) and len(root.data.layers) > 0:
use_bone_layer = True
bone_layer1_is_visible = root.data.layers[0]
root.data.layers[0] = True
if face_obj is None:
raise BaseException("Not found the Face object.")
bpy.ops.object.mode_set(mode='OBJECT')
reset_pose(root)
# add basis shape
if get_shapekey("Face", "Basis") == None:
bpy.context.view_layer.objects.active = bpy.data.objects["Face"]
bpy.ops.object.shape_key_add(from_mix=False)
# convert animation to shapekey
for action in bpy.data.actions:
if ".00" in action.name or "Emo_" not in action.name:
continue
print(action.name)
arr = action.name.split("_")
shapekey_name = action.name
# short blendshape name (uncomment if necessary)
# shapekey_name = "_".join(arr[2:])
# apply animation
root.animation_data.action = action
bpy.ops.object.visual_transform_apply()
# convert shapekay
bpy.context.view_layer.objects.active = face_obj
bpy.ops.object.modifier_apply_as_shapekey(keep_modifier=True, modifier=face_obj.modifiers[0].name)
shapekey = get_shapekey(face_obj.name, face_obj.modifiers[0].name)
shapekey.name = shapekey_name
# reset transform
reset_pose(root)
# remove all actions (uncomment if necessary)
#for action in bpy.data.actions:
# bpy.data.actions.remove(action)
if use_bone_layer:
if bpy.app.version >= (4, 0, 0):
root.data.collections[0].is_visible = bone_layer1_is_visible
else:
root.data.layers[0] = bone_layer1_is_visible
@undefined9071
Copy link
Author

undefined9071 commented Oct 13, 2023

  1. Embed facial expression clips into the model and export it as FBX: refs
  2. Import FBX into Blender (disable automated bone orientation)
  3. Execute this script

Note: Ensure that the facial expression clips correspond to the character's type

Example

  • FuXuan -> Emo_Girl
  • Seele -> Emo_Maid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment