Created
December 14, 2022 18:58
-
-
Save UuuNyaa/9a113e58adcd9b14c3e59bf78689cd5e to your computer and use it in GitHub Desktop.
Apply SMPL motion to a SMPL model.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import json | |
| import bpy | |
| from mathutils import Matrix, Quaternion, Vector | |
| SMPL_JOINT_NAMES = [ | |
| 'pelvis', # 0 | |
| 'left_hip', # 1 | |
| 'right_hip', # 2 | |
| 'spine1', # 3 | |
| 'left_knee', # 4 | |
| 'right_knee', # 5 | |
| 'spine2', # 6 | |
| 'left_ankle', # 7 | |
| 'right_ankle', # 8 | |
| 'spine3', # 9 | |
| 'left_foot', # 10 | |
| 'right_foot', # 11 | |
| 'neck', # 12 | |
| 'left_collar', # 13 | |
| 'right_collar', # 14 | |
| 'head', # 15 | |
| 'left_shoulder', # 16 | |
| 'right_shoulder', # 17 | |
| 'left_elbow', # 18 | |
| 'right_elbow', # 19 | |
| 'left_wrist', # 20 | |
| 'right_wrist', # 21 | |
| ] | |
| t2m_kinematic_chain = [[0, 3, 6, 9, 12, 15], [2, 5, 8, 11], [1, 4, 7, 10], [14, 17, 19, 21], [13, 16, 18, 20]] | |
| def to_blender_vector(smpl_xyz: Vector) -> Vector: | |
| return Vector([-smpl_xyz.x, smpl_xyz.z, smpl_xyz.y]) | |
| def to_blender_quaternion(smpl_wxyz: Quaternion) -> Quaternion: | |
| return Quaternion([smpl_wxyz.w, -smpl_wxyz.x, smpl_wxyz.z, smpl_wxyz.y]) | |
| class TestOperator(bpy.types.Operator): | |
| bl_idname = 'mmd_tools.test_operator' | |
| bl_label = 'Test Operator' | |
| bl_options = {'REGISTER', 'UNDO'} | |
| def apply_motion(self, context: bpy.types.Context, armature_object: bpy.types.Object): | |
| scale = 1.109527 | |
| pose_bones = armature_object.pose.bones | |
| motion_sample_json = bpy.data.texts['motion_sample.json'].as_string() | |
| motion_sample = json.loads(motion_sample_json) | |
| for frame, joints in enumerate(motion_sample, start=1): | |
| for bone_index_chain in t2m_kinematic_chain: | |
| chain_length = len(bone_index_chain) | |
| parent_tail_location = ( | |
| None if bone_index_chain[0] == 0 | |
| else pose_bones[SMPL_JOINT_NAMES[bone_index_chain[0]]].head | |
| ) | |
| for chain_index, bone_index in enumerate(bone_index_chain[:-1], start=1): | |
| pose_bone = pose_bones[SMPL_JOINT_NAMES[bone_index]] | |
| head_joint_location = to_blender_vector(Vector(joints[bone_index][:3]) / scale) | |
| head_location = parent_tail_location or head_joint_location | |
| tail_joint_index = bone_index_chain[chain_index] | |
| tail_joint_location = to_blender_vector(Vector(joints[tail_joint_index][:3]) / scale) | |
| quaternion = Vector((0, 1, 0)).rotation_difference(tail_joint_location-head_location) | |
| parent_tail_location = head_location + quaternion @ Vector((0, pose_bone.length, 0)) | |
| pose_bone_matrix = armature_object.convert_space( | |
| pose_bone=pose_bone, | |
| matrix=Matrix.LocRotScale(head_location, quaternion, None), | |
| from_space='WORLD', | |
| to_space='LOCAL' | |
| ) | |
| if not (pose_bone.bone.use_connect or any(pose_bone.lock_location)): | |
| pose_bone.location = pose_bone_matrix.translation | |
| pose_bone.keyframe_insert('location', frame=frame) | |
| pose_bone.rotation_quaternion = pose_bone_matrix.to_quaternion() | |
| pose_bone.keyframe_insert('rotation_quaternion', frame=frame) | |
| context.view_layer.update() | |
| def execute(self, context: bpy.types.Context): | |
| try: | |
| self.apply_motion(context, context.active_object) | |
| except Exception as ex: | |
| self.report(type={'ERROR'}, message=str(ex)) | |
| return {'CANCELLED'} | |
| return {'FINISHED'} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment