体のコントローラの値はすべて同じ値が入っているべきだと思っているので、そうなるようなスクリプトをChatGPTくんに作ってもらいました。 内容としては、 アーマチュア(PoseMode)の選択しているコントローラ(ボーン)のXYZの回転(オイラー)がズレている場合平均値を代入してくれるというものです。 Mayaと違って複数ボーンに同じ値を入れるのが結構めんどい(Alt押しながらEnter)ので。 PoseModeじゃないといけなかったり、選択しているキーフレームを取得するのが難しかったりしたので現在のフレームを対象としています。 import bpy import math # アクティブなオブジェクトを取得 active_object = bpy.context.active_object # オブジェクトが存在し、Poseモードであることを確認 if active_object and active_object.mode == 'POSE': # アクティブなポーズのフレーム番号を取得 frame_current = bpy.context.scene.frame_current # 選択されているボーンのリストを取得 selected_bones = [bone for bone in active_object.pose.bones if bone.bone.select] # ボーンごとの各軸回転の合計を初期化 total_rotation_x = 0.0 total_rotation_y = 0.0 total_rotation_z = 0.0 for bone in selected_bones: # ボーンの各軸回転を取得し合計に加算 total_rotation_x += bone.rotation_euler.x total_rotation_y += bone.rotation_euler.y total_rotation_z += bone.rotation_euler.z # 各軸の回転の平均値を計算 average_r
よくFKで肩を回転させているとき、ジンバルロックになるので、ローテーションオーダーを変更することがあります。
そのまま変更してもカーブの値はそのままなのでポーズが変わってしまいます。それを防ぐためにxformコマンドを使用するのですが、一つのキーに対してしか適用されません。
なので、選択しているオブジェクトのキー全てに対してxformコマンドを適用するようなスクリプトを作りました。
オブジェクトを選択した状態で下記のMELを実行すればできると思います。
RotationOrderを変更する前処理としてXYZがバラバラにキーを持っていたとしても、その時間にキーを挿入しています。
//一番でかい時間の値を把握する string $nodes[] = `ls -sl`; int $rotXkeyNum,$rotYkeyNum,$rotZkeyNum; //-attributeでどのアトリビュートを参照するか指定してる $rotXkeyNum = `keyframe -attribute rotateX -query -keyframeCount $nodes[0]`;//キーの数をカウントする $rotYkeyNum = `keyframe -attribute rotateY -query -keyframeCount $nodes[0]`;//キーの数をカウントする $rotZkeyNum = `keyframe -attribute rotateZ -query -keyframeCount $nodes[0]`;//キーの数をカウントする float $rotXlastTime[] = `keyframe -attribute rotateX -index ($rotXkeyNum-1) -query $nodes[0]`;//指定したインデックスの値を返す(指定したカーブの最後の時間の値を返す) float $rotYlastTime[] = `keyframe -attribute rotateY -index ($rotYkeyNum-1) -query $nodes[0]`;//指定したインデックスの値を返す(指定したカーブの最後の時間の値を返す) float $rotZlastTime[] = `keyframe -attribute rotateZ -index ($rotZkeyNum-1) -query $nodes[0]`;//指定したインデックスの値を返す(指定したカーブの最後の時間の値を返す) //冒頭のフレームに移動 スライスを時間がそれになるまで続ける currentTime -e `playbackOptions -query -min`;//再生範囲の最初 for($i=0; $i<$rotXkeyNum; $i++){ setKeyframe -at rotateY -insert -time `currentTime -q`; setKeyframe -at rotateZ -insert -time `currentTime -q`; currentTime -edit `findKeyframe -attribute "rotateX" -which next`; } currentTime -e `playbackOptions -query -min`;//再生範囲の最初 for($i=0; $i<$rotYkeyNum; $i++){ setKeyframe -at rotateX -insert -time `currentTime -q`; setKeyframe -at rotateZ -insert -time `currentTime -q`; currentTime -edit `findKeyframe -attribute "rotateY" -which next`; } currentTime -e `playbackOptions -query -min`;//再生範囲の最初 for($i=0; $i<$rotZkeyNum; $i++){ setKeyframe -at rotateX -insert -time `currentTime -q`; setKeyframe -at rotateY -insert -time `currentTime -q`; currentTime -edit `findKeyframe -attribute "rotateZ" -which next`; } currentTime -e `playbackOptions -query -min`;//再生範囲の最初 //ローテーションオーダーの値を取る $rotOrderNum = `getAttr .rotateOrder`; //キーの数が揃っているはず $rotXkeyNum = `keyframe -attribute rotateX -query -keyframeCount $nodes[0]`;//キーの数をカウントする for($i = 0; $i <$rotXkeyNum;$i++){ setAttr .rotateOrder $rotOrderNum; xform -rotateOrder xzy;//xzy setKeyframe .rotate; currentTime -edit `findKeyframe -attribute "rotateX" -which next`; }
2021/12/26追記
Animbotに全く同じ機能すでに付いていました。Animbot流石すぎる・・・。
実行したあと警告が出ますが、ローテーションオーダーを変更したことを他の人に伝えないとアニメーションの見た目が変わってしまうから。みたいな感じだと思います。
コメント
コメントを投稿