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