実行時の動画 HumanoidRig.mp4
Unity の座標系は左手系です。 左手系の座標系では、各軸回りの回転は 「その軸の無限大から原点を見て時計回りが正方向」となります。
Unity の Humanoid (人型キャラクター)の骨格は階層化されたBoneから構成されています。 Mapping で「実線の外丸は必須Bone」「点線の外丸はオプショナルBone」を表わし、 塗り潰した丸は「このHumanoidにおいて割り当てられているBone」を表わします。
Humanoid の Bone を表現する型が Unity のHumanBodyBones であり、主なBoneとして以下の種類があります。 下の表には、各 Bone の Transform の親となる Bone も "Parent Bone" として明記しました。 また、各Bone のTransform における座標軸の向きを調査したので下図に示します。
UnityのHumanoidをC#のプログラムを用いて自分で好きなように動かす方法を解説します。
"Humanoid" という "3D" 形式のプロジェクトを NEW しています。
[注意]上の操作は
Assets -> Import New Asset... -> AsianBody.fbxから行なってもよいのですが、これだとAsianBoy.fbx に必要なtextureが 自動ではimportされず、モデルが真っ白になってしまいます。 この場合は Assets/Models/Materials/に生成された白いMaterialに対応する Textureを手動でimportしなくてはいけません。
Humanoid のデータは Unity に import された段階で Animator コンポーネントが付加されています。 Animator コンポーネンント中には、人の骨格に適するようにBoneが階層化されていて、 GetBoneTransform(HumanBodyBones) 関数でその Transform を取得できます。
RigBone クラスでは指定したクォータニオン qで Transform の localRotation を変更するメソッドを用意しています。 直接クォータニオンを与えるのではなく、回転角度と回転軸を与える関数も同じ名前で用意しました。
RigBone.cs |
|
2秒周期で動作します。左上腕と左下腕は水平方向に、上腕は上下方向に振ります。 右ももと右膝は90度曲げ伸ばしを繰り返します。
各局所座標系における角度はつぎの間の値です。
Bone | 回転軸 | 最小値 | 最大値 |
---|---|---|---|
LeftUpperArm | X軸 | -80 | 80 |
LeftLowerArm | X軸 | 0 | 90 |
RigtUpperArm | Z軸 | -90 | 90 |
RigthUpperLeg | X軸 | 90 | 180 |
RightLowerLeg | X軸 | 0 | 90 |
以下のプログラムでは RigBone.set(Quaternion)関数を使って関節を曲げています。 Humanoid全体を回転させるには、humanoid.transform.rotation に世界座標系における値を設定します。 Unity Editor の Transform における Rotation の順番は Y, X, Z の順なのでここでもその順番で適用しています。
RigControl.cs |
|
Main Camera が少し離れ過ぎているので Transform Position (x,y,z)=(0,1,-2)に設定しましょう。
File -> Save Scene As ...
プログラムを実行すると、2秒周期で左手上腕、左手下腕、右手上腕、右足上腿、右足下腿が動きます。
プログラムを実行中にHierarchy ウィンドウで RigController を選択して、 RigController の Inspector ウィンドウ中の "Rig Control 2 (Script)" コンポーネントの BodyRotation を (X,Y,Z)=(0,180,0)にするとカメラ方向を向きます。
File -> Save Scene as .. -> rig2.scene
RigControl2.cs では、 RigBone クラスの offset (Quaternion) メソッドを使う 、すなわち、 Bone 毎の localRotation の初期値に対して回転を加える ように変更しています。
前の例における RigControl.cs では RigBone クラスの set() 関数 を使っていました。 すなわち、 Bone ごとの localRotation の初期値を利用せずに Bone を動かしていた ので、 Bone ごとに回転角として特別な値を設定する必要がありました。 たとえば RightUpperLeg では 0 °を設定すると足が真上を向いてしまうため、 90°から180°の間の値を設定していました。
RigControl2.cs においては RigBone クラスの offset() 関数を使うことで 初期値に対する回転を加えている ので、 どの Bone にも 0 °周辺の値を与えれば正しく動作します。 もちろん、正方向と負方向のどちらがその関節にとって自然な動きかは Bone 毎に判断が必要ですが、ずっと考えやすい方法だと思います。
ここでは各Boneには次の範囲の回転を与えています。
Bone | 回転軸 | 最小値 | 最大値 |
---|---|---|---|
LeftUpperArm | X軸 | -80 | 80 |
LeftLowerArm | X軸 | 0 | 90 |
RigtUpperArm | Z軸 | -90 | 90 |
RigthUpperLeg | X軸 | -90 | 0 |
RightLowerLeg | X軸 | 0 | 90 |
RigControl2.cs |
|
各Boneの localRotation の初期値に回転を加えているので若干ゆがんだ回転をしているようにも見えます。 しかし、こちらの方がプログラムで統一的に変形を加える方法としては、ずっと見通しがよいように思われます。
実行時の動画 HumanoidRig2.mp4
ここで説明した Unity のプロジェクトファイルはこちら Humanoid.zip。