2017年3月26日日曜日

【Unity5】キャラモーションをリミテッドアニメにする  ~ 再生フレーム指定編 ~

前回のボーントレース編に続き、今回はアニメーションクリップの再生位置を指定する方法でリミテッドアニメ化してみます。

使う素材は前回と同じく、プロ生ちゃんの【PronamaChan_Ver3.unitypackage】 と、スタンダードアセット【Characters】 に入っているアニメーションクリップ【HumanoidRun】 です。インポート方法は前回記事を参照してください。
※Unity 5.5.2f1 (64-bit)を使用しています。




キャラクターを準備


【PronamaChan】 > 【Prefabs】 > 【Normal】 > 【Standard】
にある、【PronamaChan_dynamic】を【Hierarchy】に配置。

【Standard Assets】 > 【Characters】 > 【ThirdPersonCharacter】 > 【HumanoidRun】にある
【HumanoidRun】を【Hierarchy】の【Pronamachan_Dynamic】にドラッグ&ドロップ。

プロ生ちゃんが走り去ってしまわないように
【PronamaChan_dynamic】の【Inspector】 > 【Animator】の【Apply Root Motion】のチェックを外しましょう。

今回のスクリプト【LimitedAnimationByPlayClipFrame.cs】


【project】に【C# Script】を新規追加し、「LimitedAnimationByPlayClipFrame 」という名前に変更、ダブルクリックしてファイルを開き、下記の内容に書き換えて保存。

【LimitedAnimationByPlayClipFrame.cs】
using UnityEngine;
using System.Collections;
public class LimitedAnimationByPlayClipFrame : MonoBehaviour
{
       //各要素1フレームとして、-1は更新しないフレーム、それ以外の数字は描画するフレーム位置を指定
       public int[] timesheet = new int[] { 0, -1, -1, -1, -1, 5, -1, -1, -1, -1, 10, -1, -1, -1, -1, 15, -1, -1 };
       private Animator m_animator;
       private AnimationClip clip;
       private int animationHash;
       void Awake()
       {
              //アニメーションクリップの情報をゲット
              m_animator = GetComponent<Animator>();
              clip = m_animator.GetCurrentAnimatorClipInfo(0)[0].clip;
              animationHash = m_animator.GetCurrentAnimatorStateInfo(0).shortNameHash;
              m_animator.speed = 0;
       }

       void LateUpdate()
       {
              if (IsDrawFrame(Time.frameCount))
              {
                     DrawAnimationFrame(timesheet[Time.frameCount % timesheet.Length]);
              }
       }
       //アニメーションクリップの指定時間のフレームを静止再生
       void DrawAnimationFrame(int drawFrame)
       {
              //アニメーションクリップの長さを1とした時のフレームの位置
              float normalizedtime = ((float)drawFrame / clip.frameRate / clip.length);
              m_animator.Play(animationHash, 0, normalizedtime);
       }
       //ポーズを更新するフレームかどうかチェック
       bool IsDrawFrame(int checkFrame)
       {
              if (timesheet[checkFrame % timesheet.Length] >= 0)
              {
                     return true;
              }
              return false;
       }

実際、アニメーションクリップは複数あったりするものですが、今回は実験なのでアニメーションクリップは一つだけの想定のスクリプトになってます。
結果、あまり汎用性がないのでご注意ください。

このスクリプトを【Hierarchy】の【Pronamachan_Dynamic】にアタッチし、
【Inspectr】の【Timesheet】に使用するフレームの情報を入力します。
【Size】はループするフレーム数と思ってください。以下【Element】が各フレームで、値がアニメーションクリップのフレームナンバーです。

【-1】はポーズの更新なし、つまり前の絵のままのフレームです。
【0】以上の値はフレームナンバーで、元のクリップのフレーム数より大きい値も入ります。
10フレームしかないアニメーションクリップで15と入れたら、5フレーム目が使われます。
ちなみに今回使ったアニメーションクリップ【HumanoidRun】は【clip.framerate】が「30」で長さ【clip.length】は「0.593」なので、フレーム数換算で19程度です。

もちろん数字を順番に入れる必要はないので、唐突に違うフレームを差し込んだりできます。

これで再生してみると、スカートなどの揺れ物以外はコマ落ちして再生できます。
この方法とボーントレースを組み合わせて、両者の欠点を補えれば・・・。

Blender上でMIDIファイルを読み込み3Dモデルの鍵盤を動かすpythonスクリプトに挑戦したこと

昔取り組んだことについての忘備録 作成日 2016/8/7 目的 MIDIファイルの仕様の理解 BlenderとPythonの学習 内容 MIDIファイルのバイナリを読み込んで解析し、ノートオン、ノートオフ情報に従って、対応する音階の...