コンテンツにスキップ

参考4-2: スクリプトによる位置ずれ・回転ずれの補正

回転の調整はかなり難しい

演習4-2で説明したmixamorig:Hipsのパラメータを調整するような操作では, 回転を調整するのは少し難しいです.

スクリプトによる位置ずれ・回転ずれの補正

演習4-3では,スクリプトでモーションデータをプログラム処理できることを確認しました.

この処理を応用して,位置ずれ・回転ずれを補正するためのプログラムを適用しています.

以下のサンプルファイルをダウンロードしてください.

補正用のスクリプトについて

テンプレートファイルには,以下のスクリプトが事前に設定されています.

import bpy
from mathutils import Vector, Quaternion
import math

def get_pose(bones, frame):
    bpy.context.scene.frame_set(frame)
    bpy.context.view_layer.update()
    pose = []
    for i, bone in enumerate(bones):
        location = bone.location.copy()
        scale = bone.scale.copy()
        rotation_quaternion = bone.rotation_quaternion.copy()
        pose.append([location, scale, rotation_quaternion])
    return pose

def set_pose(bones, pose, frame):
    bpy.context.scene.frame_set(frame)
    for i, bone in enumerate(bones):
        location, scale, rotation_quaternion = pose[i]
        if i == 0:
            print(f"Set: {frame}: {location}")
        bone.location = location
        bone.scale = scale
        bone.rotation_quaternion = rotation_quaternion

        bone.keyframe_insert(data_path="location", frame=frame, group=bone.name)
        bone.keyframe_insert(data_path="scale", frame=frame)
        bone.keyframe_insert(data_path="rotation_quaternion", frame=frame)

    bpy.context.view_layer.update()


def root_offset(armature_name, frame_start, frame_end):
    armature = bpy.data.objects[armature_name]

    bones = armature.pose.bones

    bone = bones[0]

    print(f"bone: {bone.name}")

    bpy.context.scene.frame_set(frame_start)

    M = armature.matrix_world
    M_inv = M.inverted_safe()

    Pw = armature.location @ M.inverted_safe()
    Pw[2] *= -1

    Q_90 = Quaternion((1.0, 0.0, 0.0), math.radians(90.0))

    Q = M.to_quaternion()

    Q = Q_90.inverted() @ Q
    R = Q.to_matrix()

    Pw = R.inverted_safe() @ Pw

    P1 = bone.head


    for frame in range(frame_start, frame_end + 1):
        bpy.context.scene.frame_set(frame)


        Pi = bone.location + Pw
        Pi = R @ Pi    
        bone.location = Pi


        Qi = bone.rotation_quaternion.copy()
        Qi = Q @ Qi
        bone.rotation_quaternion = Qi

        bone.keyframe_insert(data_path="location", frame=frame)
        bone.keyframe_insert(data_path="rotation_quaternion", frame=frame)
        bpy.context.view_layer.update()

    # Rest translations, rotations
    armature.location = Vector((0, 0, 0))
    armature.rotation_euler = Vector((math.radians(90.0), 0, 0))
    bpy.context.view_layer.update()


bpy.ops.object.mode_set(mode='POSE')
root_offset("Armature.001", 1, 17)
bpy.ops.object.mode_set(mode='OBJECT')

利用方法

  1. Objectモードにしてモーションの位置・向きを変更したいArmatureを選択
  2. Armatureの位置・向きを好きな設定に移動する
    • Armatureの位置が変わっていることを確認する
  3. root_offset.pyのスクリプトを実行する
    • root_offset(armature_name, start_frame, end_frame)
    • 向きを調整したいArmatureの名前を適切に指定する
    • start_frame, end_frameの設定をキーフレーム登録状況に合わせる
    • アクション実行後⇨位置・向きが変化している
  4. NLA Editorでブレンドする

RootOffset_Transform RootOffset_Setting