今回はBlenderで作成したキャラクターにシェイプキーを使って顔のアニメーションを作成し、それをUnityで使ってみたいと思います。
以前にボーンを操作して顔のアニメーションを作成してUnityで使いましたが、

今回はボーンを使ったアニメーションではなく直接メッシュの頂点の位置を動かして作るシェイプキーのアニメーションを使って顔のアニメーションを作成します。
シェイプキーで顔のアニメーションを作成する前にキャラクターにモディファイアを取り付けている場合はアーマチュアモディファイア以外のモディファイア(例えばミラーモディファイア)を適用させておいてください。
モディファイアが残っているとFBXとしてファイル出力する時にシェイプキーのエクスポートがおかしくなるようです。
今回の記事では以下のようにBlenderで作成したシェイプキーを使ったアニメーションがUnityでも使えます。
上の例ではAnimatorControllerのレイヤーとアバターマスクを使って顔だけのアニメーションを再生させています。
Blenderで顔のアニメーションを作成する
まずはBlenderのシェイプキーを使ってキャラクターの顔のメッシュを移動させてアニメーションを作成していきます。
まずはオブジェクトモードで顔を含むオブジェクトを選択し、オブジェクトデータプロパティのシェイプキーの右の+を押します。
するとシェイプキーにベースが追加されます。
このベースが元の形状になります。
続けてシェイプキーの右の+を押して新しく出来たキー1の名前を変えてBlink(瞬き)とします。
Nキーを押してサイドバーを表示し、ツールのミラーのXを有効にします。
Blinkを選択した状態でTabキーを押して編集モードにし、目を閉じるように頂点を選択して移動させます。
瞼にあたる部分の頂点を選択し、目を閉じるように下に移動させます(ミラーのXを有効にしたので片方の頂点を移動すると反対側も同じように動きます)。
完全に目を閉じるように移動させます。
シェイプキーを使う時は頂点の数は変更せず位置だけを変更するようにします。
ここまで出来たら瞬きのアニメーションを作成していきます。
Tabキーを押してオブジェクトモードに戻ります。
タイムラインの1フレーム目に移動します。
オブジェクトデータプロパティのシェイプキーのBlinkを選択し、値を0にし、その値の上でキーボードのIキーを押してキーフレームを打ちます。
次にタイムラインの5フレームに移動させ、オブジェクトデータプロパティのシェイプキーのBlinkを選択し、値を1にした状態でキーボードのIキーを押してキーフレームを打ちます。
10フレーム目に移動し、シェイプキーのBlinkを選択し、値を0にした状態でIキーを押してキーフレームを打ちます。
これで1フレームから10フレームまでで瞬きをするアニメーションが出来ました。
シェイプキーアニメーションがうまく出力されない!
これで瞬きのアニメーションが出来ましたが、このままシェイプキーのアニメーションだけを出力しようとしてもUnityで反映されなかったので、適当にボーンを動かして体のアニメーションも作成します。
タイムラインの1フレーム目に移動し、ポーズモードにしたら左手のIKを選択しIキーを押して位置/回転をキーフレームに打ちます。
10フレーム目に移動し、左手のIKを選択し適当に移動させてIキーを押し、位置/回転をキーフレームに打ちます。
通常のアニメーションとシェイプキーを組み合わせる場合はボーンで作成するアニメーションをちゃんと作ってください。
今回は顔のアニメーションしか使わないので胴体は適当に動かしました。
FBXファイル出力
Blenderのファイルメニューからエクスポート→FBXを選択します。
オブジェクトタイプをアーマチュアとメッシュのみShiftキーを押しながら選択します。
スケールを適用ではすべてFBXにし、出力します。
UnityでFBXファイルを取り込み設定をする
出力したらUnityのAssetsフォルダ内で右クリックからImport New Assetを選択し出力したFBXファイルを取り込みます。
取り込んだらファイルを選択し、インスペクタのModelタブでImport BlendShapesにチェックが入っているのを確認します(デフォルトで入っているはず)。
次にRigタブを選択しAnimation TypeをHumanoidにしApplyボタンを押します。
Animationタブを選択し、取り込んだアニメーションが正常に動作するか確認します。
また、瞬きアニメーションは繰り返し再生したいのでLoop Timeにチェックを入れApplyを押します。
以下のように瞬きと手の動きがUnityでも再生されているのを確認します。
ここで複数のいらないアニメーションが取り込まれてしまった場合はそのアニメーションを選択し、-を押してそのクリップを削除します。
わたくしの場合はうまい具合にひとつのアニメーションだけが取り込まれたので削除はしませんでした。
顔のアニメーションだけを使う
今回使用するのは顔のアニメーションだけなのでアバターマスクとAnimatorControllerのレイヤーを使って顔のアニメーションだけを上書きする事にします。
Assetsフォルダ内で右クリックからAvatar Maskを選択し、名前をHeadAvatarMaskとし、インスペクタで頭だけを緑色にして有効にします。
AnimatorControllerはBase LayerでIdle状態とWalk状態を作りアニメーションパラメータ―Speedの値によってアニメーションを切り替えているとします。
新たにレイヤーを作成し、名前をHeadとします。
Headレイヤーを選択し、右の歯車を押したらWeightを1にし、Avatar Maskに先ほど作ったHeadAvatarMaskを設定し、Syncにチェックを入れてBase Layerと同期し同じ状態と遷移が表示されるようにします。
HeadレイヤーはHeadAvatarMaskを設定したので顔のアニメーションだけが再生されます。
さらにBlendingをOverrideにしているので、Source Layerに設定しているBase Layerのアニメーションを上書きします。
HeadのIdle状態を選択し、インスペクタに先ほど取り込んだキャラクターのアニメーションクリップを設定します。
HeadのWalkには何も設定しません。
これで機能が出来ました。
キャラクターが立ち止まっている時は瞬きをしますが、歩いている時は瞬きをしないようになりました。
スクリプトからシェイプキーの値を変更する
シェイプキーはUnityのSkinned Mesh RendererのBlendShapes項目に表示されるようになります。
わたくしの場合は瞬き(Blink)の他に口を開ける(MouseOpen)も作ったので上のように二つのシェイプキーが表示されます。
スクリプトからシェイプキーの値を操作するとAnimatorControllerに顔用のレイヤーを作ったりアバターマスクを作って設定しなくても出来ます。
その分スクリプト側でシェイプキーの値を操作する必要があります。
新しくShapeKeyOperationsスクリプトを作成し、キャラクターに取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class ShapeKeyOperations : MonoBehaviour { private SkinnedMeshRenderer skinnedMeshRenderer; private float blinkCount; [SerializeField] private float blinkSpeed = 5f; // Start is called before the first frame update void Start() { skinnedMeshRenderer = transform.Find("kamekume").GetComponent<SkinnedMeshRenderer>(); // MouseOpen(今回はなにもしない) skinnedMeshRenderer.SetBlendShapeWeight(0, 0f); // Blink skinnedMeshRenderer.SetBlendShapeWeight(1, 0f); } // Update is called once per frame void Update() { // 0~100の間のウエイト値を生成 blinkCount = Mathf.Clamp01(Mathf.Sin(Time.time * blinkSpeed)) * 100f; skinnedMeshRenderer.SetBlendShapeWeight(1, blinkCount); } } |
Startメソッドでキャラクターの子要素のシェイプキーで操作しているメッシュのSkinnedMeshRendererコンポーネントを取得し、それぞれのシェイプキーを0(ベースの状態)に設定しています。
UpdateメソッドではMathf.Sinで‐1~1の値を取得し、それをMathf.Clamp01で0~1の間に調整し、それに100をかけて0~100の間の値を作っています。
Blenderのシェイプキーの値がUnityでは0~100の間で対応されます。
シェイプキーのBlinkの値にこの0~100の値を入れる事で定期的に瞬きをするようにしています。
実行すると以下のようにスクリプトで瞬きをするようになりました。
スクリプトの場合はアニメーションの状態を考慮していないのでどの状態でも一定間隔で瞬きをします。