Unity のアニメーションシステムは、スキンメッシュされたキャラクターの素晴らしいアニメーションを可能にします。アニメーションシステムは、アニメーションのブレンド、ミキシング、加算的アニメーション、歩行周期の同期、アニメーションのレイヤー、さまざまな方法によるアニメーション再生の制御(時間、速度、ブレンドウェイト)、頂点ごとに1、2 または 4 ボーンを割り当てたメッシュスキニングだけでなく、物理ベースのラグドールと、プロシージャルなアニメーションもサポートしています。最良の結果を得る為に、Unity で最適なパフォーマンスのリグキャラクターを作成するための、最良の練習方法と技法について書かれた最適なパフォーマンスのためのキャラクターモデリングのページを読む事をお勧めします。
快活なキャラクターの作成は、ゲーム空間を 移動 させ、必要に応じて適切な アニメーション をさせる、という、2つの要素から成り立っています。キャラクターの移動に関してもっと知りたい場合は、キャラクターコントローラーに目を通してください。このページでは、アニメーションに焦点をあわせています。事実上、キャラクターのアニメーティングは Unity のスクリプトインターフェースを通して行われます。
快活なキャラクターの事前設定を公開しています。実例デモでダウンロードできます。このページで基礎を学んだ後、アニメーションスクリプトインターフェースを参照することもできます。
こんにちのゲームは、アニメーションのブレンディングが、キャラクターをスムーズにアニメーションすることを保証する、必要不可欠な機能になっています。アニメーターが、例えば、歩く繰り返し、走る繰り返し、アイドリングのアニメーションか射撃のアニメーションとアニメーションを分けて作成します。ゲーム中のどの時点でも、アイドルアニメーションから歩行サイクルまたはその逆へと、望みの移行をすることができます。当然、スムーズにし突然の急な動きは避ける移行を望んでいます。
ここでアニメーションのブレンディングの出番です。Unity 内では、同じキャラクター上のアニメーション再生の番号をいくつも持つ事ができます。すべてのアニメーションは、混ぜたか追加した、ともに最終のアニメーションで生成します。
最初のステップは、アイドルから歩行アニメーションへの、なめらかなキャラクターブレンドを作成できる様にすることです。スクリプトでの作業を楽にするために、まずアニメーションの Wrap Mode を Loop に設定します。それから、スクリプトがアニメーションを一つだけ再生するかどうか確認するために Play Automatically をオフにしておきます。
最初のアニメーティングキャラクター向けのスクリプトは、割と単純です。どうやって早くキャラクターが動いているか、見いだすための方法のみ必要です。その後、歩くからアイドルへゆっくりアニメーションします。簡単なテストのために、標準の入力軸を使う事にします。
function Update () {
if (Input.GetAxis("Vertical") > 0.2)
animation.CrossFade ("walk");
else
animation.CrossFade ("idle");
}
あなたのプロジェクトで、このスクリプトを使うには:
プレイボタンを押すと、キャラクターは、上の矢印キーを押し続けで場所内を歩き始め、離すとアイドルポーズに戻ります。
レイヤーは、グループアニメーションと重み付け優先順位を付けることで、非常に有用な概念です。
Unity のアニメーションシステムでは、すきなだけ沢山のアニメーションクリップをブレンドする事ができます。手動でブレンドウェイトを設定する事もできますが、ウェイトを自動的にアニメーションさせる animation.CrossFade() を使うと簡単です。
例えば、歩く繰り返しと走る繰り返しが在ったとします、両方とも 1(100%)の重さを持っています。Unity が最後のアニメーションを生成するときそれは正規化された重さになり、歩く繰り返しのアニメーションに 50%を与え、走る繰り返しにも 50%が与えられる事ということです。
ですが、大抵の場合、2 つのアニメーションを再生したときに、どちらのアニメーションにより重みをつけるか、優先度を設定したいと思うでしょう。もちろん手動で重みの合計値を 100% にすることも可能ですが、この目的であればレイヤーを使う方が、より簡単です。
例えば、射撃、それにアイドルと歩行サイクルのアニメーションがあるとします。歩行とアイドルのアニメーションは、プレイヤーの速度をベースにブレンドされますが、プレイヤーが射撃するときは、射撃アニメーションだけを再生したくなります。従って、基本的に射撃アニメーションの優先順位が高い、という事になります。
これを行う簡単な方法は、単純に射撃中に歩行とアイドルアニメーション再生し続けることです。これを行うには、射撃アニメーションが、アイドルと歩行アニメーションより高いレイヤー内に、作成されているか確認する必要があります、つまり射撃アニメーションは、最初の重さ配合を受けるであろうことを意味します。射撃アニメーションが 100%、重みの配合を使っていない場合に限り、歩行とアイドルアニメーションは、重さを受け取る事ができます。そんなわけで、射撃アニメーションでクロスフェーディングするとき、重さは 0 から始まり短い期間で 100%に近づきます。最初のうちは、まだ歩行とアイドルレイヤーが配合された重さを受けとりまが、完全に射撃アニメに移行したときには、まったく重みを受け取りません。これは、まさに我々が望んだものです!
function Start () {
// Set all animations to loop
animation.wrapMode = WrapMode.Loop;
// except shooting
animation["shoot"].wrapMode = WrapMode.Once;
// Put idle and walk into lower layers (The default layer is always 0)
// This will do two things
// - Since shoot and idle/walk are in different layers they will not affect
// each other's playback when calling CrossFade.
// - Since shoot is in a higher layer, the animation will replace idle/walk
// animations when faded in.
animation["shoot"].layer = 1;
// Stop animations that are already playing
//(In case user forgot to disable play automatically)
animation.Stop();
}
function Update () {
// Based on the key that is pressed,
// play the walk animation or the idle animation
if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1)
animation.CrossFade("walk");
else
animation.CrossFade("idle");
// Shoot
if (Input.GetButtonDown ("Fire1"))
animation.CrossFade("shoot");
}
デフォルトでは、animation.Play() と animation.CrossFade() は、同じレイヤー内にあるアニメーションを停止したり、フェードアウトできます。これこそが、多くの場面で必要な機能です。射撃、アイドル、走行の例において、アイドルと走行の再生は、射撃アニメーションに影響しませんし、その逆も同様です(望むならこの振る舞いは、animation.CrossFade のオプションパラメーターで変更できます)。
アニメーションミキシングは、いくつかのアニメーションを身体の一部のみに適用することで、ゲーム作成に必要なアニメーションの数を削減することを可能にします。これは、そんなアニメーションが他のアニメーション内のさまざまな組み合わせとともに使えることを意味します。
AnimationState が与えられた AddMixingTransform() を呼び出すことにより、アニメーションへアニメーションミキシング変換を追加する。
手を振るアニメーションを例として、ミキシングを考えてみます。キャラクターがアイドリング状態のときと歩行状態のときに、手を振らせたいとしましょう。アニメーションミキシング無しでは、アイドリング状態と歩行状態それぞれ用に、手を振るアニメーションを分けて作成しなくてはなりません。ですが、肩のトランスフォームに手を振るアニメーションをミキシングすれば、肩から手までの部分だけを、手を振るアニメーションで制御する事ができます。その場合、体の残りの部分は、手を振るアニメーションには影響されず、アイドルか歩行アニメーションを再生し続けます。従って、この場合、手を振るアニメーションを一つだけ作成すれば良いことになります。
/// Adds a mixing transform using a Transform variable
var shoulder : Transform;
animation["wave_hand"].AddMixingTransform(shoulder);
もう一つの例、パスを使用する
function Start () {
// Adds a mixing transform using a path instead
var mixTransform : Transform = transform.Find("root/upper_body/left_shoulder");
animation["wave_hand"].AddMixingTransform(mixTransform);
}
加算的アニメーションとアニメーションミキシングは、ゲーム作成に必要なアニメーションの数を削減することを可能にします、そして、フェイシャルアニメーションの作成にとっても重要です。
歩行中や走行中に、ターンのため一方に体を傾けるような、キャラクターを作成したいとします。これには、4 つの組み合わせ(歩く-傾く-左、歩く-傾く-右、走る-傾く-左、走る-傾く-右)、それぞれのアニメーションが必要になります。それぞれの組み合わせ用に、個別のアニメーションを作成するのは、このシンプルな事例ですら、明らかに多くの余計な仕事をもたらしますが、アクションが増えると、組み合わせの数はさらに増加します。幸いなことに、加算的アニメーションとミキシングは、単純な動きを組み合わせるための、この個別アニメーションの製作を不要にします。
加算的アニメーションは、その他の再生するかもしれない一つのアニメーションエフェクトに、重ねることを許しています。加算アニメーションを生成するとき、Unity は最初のフレーム内のアニメーションクリップと現在のフレーム間の違いを計算します。それから、他すべての再生しているアニメーションの最上位上の違いを問い合わせます。
先程の例を参考にしてみると Unity の世界で、歩く、アイドルか走るサイクルこれらの上に右と左に体を曲げるアニメーションの作成ができました。これは、次のようなコードで達成することができます。
private var leanLeft : AnimationState;
private var leanRight : AnimationState;
function Start () {
leanLeft = animation["leanLeft"];
leanRight = animation["leanRight"];
// Put the leaning animation in a separate layer
// So that other calls to CrossFade won't affect it.
leanLeft.layer = 10;
leanRight.layer = 10;
// Set the lean animation to be additive
leanLeft.blendMode = AnimationBlendMode.Additive;
leanRight.blendMode = AnimationBlendMode.Additive;
// Set the lean animation ClampForever
// With ClampForever animations will not stop
// automatically when reaching the end of the clip
leanLeft.wrapMode = WrapMode.ClampForever;
leanRight.wrapMode = WrapMode.ClampForever;
// Enable the animation and fade it in completely
// We don't use animation.Play here because we manually adjust the time
// in the Update function.
// Instead we just enable the animation and set it to full weight
leanRight.enabled = true;
leanLeft.enabled = true;
leanRight.weight = 1.0;
leanLeft.weight = 1.0;
// For testing just play "walk" animation and loop it
animation["walk"].wrapMode = WrapMode.Loop;
animation.Play("walk");
}
// Every frame just set the normalized time
// based on how much lean we want to apply
function Update () {
var lean = Input.GetAxis("Horizontal");
// normalizedTime is 0 at the first frame and 1 at the last frame in the clip
leanLeft.normalizedTime = -lean;
leanRight.normalizedTime = lean;
}
ヒント: 加算的アニメーションを使う場合、すでに加算的アニメーションが使われている各トランスフォーム上で、非加算的アニメーションも再生するのはやめた方が良いです。この場合、アニメーションは最終フレームの結果の上に追加されてしまい、全く望まない結果となってしまいます。
時には、あなたのキャラクターのボーンを手順に沿って動かしてみたくなります。例えば、ターゲットの位置をトラックするスクリプトで、3D 空間の目標位置にあなたのキャラクターの頭が追従するのに最善な方法はどれかと思うかもしれません。幸いな事に Unity は、これらをとても簡単に作成します、ボーンからどのスキンメッシュが動いて変換するだけかだけです。したがって、GameObject の Transform の要領で、スクリプトでキャラクターのボーンを制御できます。
ひとつ知ってもらいたい重要な事が、アニメーションシステムの更新は、Update() 関数の変換後と LateUpdate() 関数の前と言う事です。したがって、もし、LookAt() 関数をつかいたい場合、LateUpdate() 関数内で本当にアニメーションが上書きしているのか確認する必要があります。
ラグドールは同じ方法で作成されます。単純に、キャラクタージョインと異なるボーンのカプセルコライダーへ Rigidbody をアタッチする必要があります。これで、キャラクターの皮膚は、物理的なアニメーションをすることができでしょう。
このセッションは、プレイバックエンジンでサンプルしたときに、どのように Unity 内でアニメーションするのかを説明します。
アニメーションクリップは、一般的に固定フレームレートで作成されます。例えば、3ds Max や Maya では、アニメーションを 60 フレーム / 秒 (fps) で作成できますが、 Unity にそのアニメーションをインポートすると、インポーターがフレームレートを読み取るので、インポートされたアニメーションも 60fps でサンプリングされます。
ですが、一般的にゲーム実行時のフレームレートは変動します。あるコンピューターでは他のコンピューターよりもフレームレートが高いかもしれませんが、次の瞬間には、視界に映っているものの複雑さから、変化してしまうかもしれません。これは、基本的にゲーム実行時の正確なフレームレートを推定するのは困難である事を意味します。つまり、アニメーションを 60fps で作成したとしても、異なるフレームレート、例えば 56.72fps、とか 83.14fps、もしくは全く違う値で再生されるかもしれないのです。
結果として Unity は、可変フレームレートでアニメーションをサンプルする必要があり、そのためにもともと設計されたフレームレートを保証していません。幸いなことに 3D コンピューターグラフィックスアニメーションは、個々のフレームから成り立っている訳ではなく、連続したカーブになっています。これらのカーブは、オリジナルのアニメーション内のフレームと一致しない、任意の時点でサンプルすることができるため、事実、アニメーション製作時より高いフレームレートでゲームを実行すると、アニメーションソフトウェア上よりもゲーム内のほうが、本当にスムーズでより流れるように滑らかなアニメーションに見えるでしょう。
多くの実用的な目的により、Unity がアニメーションを可変フレームレートでサンプルするのを、無効にできます。しかし、トランスフォームやプロパティーに非常に特殊な設定をもつアニメーションに依存するゲーム実行ロジックを使用している場合、シーンの裏側で、再度サンプリングが行われている事を知っておく必要があります。例えば、0 から 180 度まで回転するオブジェクトで 30 フレーム以上のアニメーションがあり、半分に達したときにそれをコードから知りたい場合、現在の角度が 90 度かどうかの確認をコードからするべきではありません。なぜなら、Unity は、ゲームの可変フレームレートのようにアニメーションをサンプルするので、回転がちょうど 90 度のときにサンプルし、次回、また90 度に達した直後もサンプルされてしまうからです。アニメーションが指定した位置に達した通知が必要な時は、アニメーションイベントを代わりに使うべきです。
またこれは、可変フレームレートのサンプリングも同様で、WrapMode.Once を使って再生しているアニメーションでは、正しい最終フレームがサンプリングされていないかもしれません。ゲームの 1 フレーム中では、アニメーションのサンプリングはアニメーションがぴったり終わる前に行われる事があり、その場合、次のフレームはアニメーションの長さを超えた時間上になってしまうので、超えた分はサンプリングされません。アニメーションの最終フレームを絶対確実にサンプリングしたい場合は、アニメーションを明示的に停止するまで最終フレームをサンプリングし続ける WrapMode.ClampForever を使ってください。