MRが楽しい

MRやVRについて学習したことを書き残す

Blenderで作成した3DモデルをUnityに取り込む その3

前回記事の続きです。
bluebirdofoz.hatenablog.com

今回は「position, rotation, scale といったTransformコンポーネントのデフォルト値が 1 でない」の問題の続きです。
前回で解決したと思ったら、完全には解決していなかったので再調査を実施しました。

前回は以下のスケール値のリセットを試しました。
tumo-blendermemo.blogspot.jp

これを実施して、以下のようにBlender内の要素を全て選択して.fbxファイルにエクスポートします。
f:id:bluebirdofoz:20170730231404j:plain

これを取り込むと、一見トランスフォームが綺麗に初期化されたように取り込まれます。
f:id:bluebirdofoz:20170730231418j:plain

しかし、その実。オブジェクトの中にあるメッシュ自体は微妙にトランスフォームが完全には初期化されていませんでした。
f:id:bluebirdofoz:20170730231430j:plain
必ず、この値になっています。

 Position      0   0   0
 Rotation -89.98   0   0
 Scale       100 100 100

当然ながら Blender での出力の際、メッシュのみを選択すると本オブジェクトが本設定で出力されてしまいます。
f:id:bluebirdofoz:20170730231441j:plain
これでは意図した初期化が行えたとは言えません。


この問題を解決するため、以下の手順を実施しました。
waken.hatenablog.com

手順は簡単です。エクスポートの際、以下の「トランスフォーム適用」にチェックを入れて出力します。
f:id:bluebirdofoz:20170730231509j:plain

Unity に取り込んでみると……。
f:id:bluebirdofoz:20170730231521j:plain
今度はメッシュのトランスフォームも初期化できています。これでようやく問題解決です。

次回こそは「ゴーグル部分の透過が行われていない」の問題の解決です。
bluebirdofoz.hatenablog.com

Blenderで作成した3DモデルをUnityに取り込む その2

前回記事の続きです。
bluebirdofoz.hatenablog.com

今回解決するのは検出された問題の2点目です。
次は「position, rotation, scale といったTransformコンポーネントのデフォルト値が 1 でない」を解決します。
f:id:bluebirdofoz:20170730014741j:plain

少し調べたところ、位置情報のリセット方法について下記の情報を発見しました。
tumo-blendermemo.blogspot.jp

早速試してみましょう。移動・回転・拡大縮小の全てを適用します。
f:id:bluebirdofoz:20170730015946j:plain

結果、トランスフォームの値が全て 0 または 1 に初期化されました。
f:id:bluebirdofoz:20170730015955j:plain

再びFBX形式でエクスポートしてUnityに取り込んでみると……。
f:id:bluebirdofoz:20170730020002j:plain
Transformの値が全て初期化されています。この設定が対応付いていたようですね。


さて Transform の値は初期化されましたが、現状の hololens のモデルはUnity世界比で大きいという問題があります。
ユニティちゃんを取り込んで比較してみました。
f:id:bluebirdofoz:20170730020011j:plain
デカ過ぎです。あまりに hololensが大きくてカメラ映像で見ると遠近感が狂います。
hololensとユニティちゃんの大きさを、頭にセットできる適切なサイズ比としたいところです。

さてこのとき、大きさの基準を何にするかという問題があります。
今回、基準とすべきはUnityの距離単位 Unit です。
unitter.net

これによると、1Unit = 1メートルとのことです。
これまでも 1 = 1m という話は何度かしましたが、この基準を使っていたという事ですね。

サイズ比が分かりやすいよう。デフォルトで作成すると 1 × 1 × 1 の大きさで生成される Cube オブジェクトを並べてみました。
f:id:bluebirdofoz:20170730020022j:plain
これと比較するとユニティちゃんは約 1.5 ほどの大きさです。
ユニティちゃんが凡そ人と同じ大きさとすると、1.5m ほどであり、このUnit基準を元に大きさが決められていると分かります。


であれば、hololens側の大きさを調整してUnit基準に合わせるべきです。
早速、Blenderを開きます。……と、ここで気付きました。
f:id:bluebirdofoz:20170730020034j:plain
この「寸法」という値は何でしょう。先ほどのユニティちゃん比を鑑みるとメートル基準の大きさっぽいですが……。

調べてみたところ、Blenderはこの寸法の単位について、基準の大きさを決められるようです。
blender3d.isopro91.com

プロジェクトの単位設定を確認したところ、デフォルトでは「長さ:なし」「単位倍率:1.000」になっていました。
f:id:bluebirdofoz:20170730020042j:plain
しかし、現状のサイズ比をみると、何となく、そのままでも Unity と基準が同じメートル法な気がします。

試しにメートル法と仮定して寸法の値を変更してみます。
hololensの実サイズは……と調べてみましたが公式なサイズ情報が見つかりませんでした。
www.microsoft.com
仕方ないので定規で実物を計りました。19cm × 28cm × 8cm くらいでしょうか。形が流線型で図るの難しい。

凡そ「寸法」が X: 0.19, Y: 0.28, Z: 0.08 に近づくよう大きさを変更します。
各値を直接変更してしまうと、モデルが歪んでしまうので全体のサイズ調整で近しい大きさにします。
f:id:bluebirdofoz:20170730020051j:plain

改めて「拡大縮小」を適用してFBX形式でエクスポート、Unityに取り込みます。
f:id:bluebirdofoz:20170730020102j:plain
おお。それっぽい大きさ比です。Transformの値も問題ありません。

試しに位置合わせを行い、ユニティちゃんに被せてみました。
f:id:bluebirdofoz:20170730020112j:plain
ぴったりです。Transformの問題と大きさの問題について解決しました。


次回は「ゴーグル部分の透過が行われていない」の問題の解決にトライします。
bluebirdofoz.hatenablog.com

Blenderで作成した3DモデルをUnityに取り込む その1

さて今回は技術調査枠です。
Blenderで自作したhololensモデルをUnityに取り込んで使ってみます。
bluebirdofoz.hatenablog.com
bluebirdofoz.hatenablog.com

なるべくシンプルなものを利用したいので今回は法線マップ適用前のモデルを利用します。
Blenderのプロジェクトを開き、ファイル -> エクスポート -> fbx を選択し、FBX形式でファイルを出力します。
f:id:bluebirdofoz:20170729185401j:plain

今回利用するのは見た目のポリゴンのみなので、「メッシュ」を選択してエクスポートします。
f:id:bluebirdofoz:20170729185433j:plain

そしてエクスポートした.fbxファイルをUnityに取り込みます。
f:id:bluebirdofoz:20170729185446j:plain

さて、パッと見たところ以下の3つの問題が発生しました。
1.テクスチャが取り込まれておらず、見た目が真っ白になる。
2.position, rotation, scale といったTransformコンポーネントのデフォルト値が 1 でない。
  (後、Unity世界の 1 = 1m 比だと実物のhololensよりメチャでかい)
3.ゴーグル部分の透過が行われていない。

これらの問題について一つづつ解決していきます。
今回は1つ目「テクスチャが取り込まれておらず、見た目が真っ白になる」の解決です。

こちらについてはMMDモデルの.fbxファイル取り込み時に発生していました。
.fbxファイルにはテクスチャファイルは含まれていません。別途、参照先にテクスチャを用意してやる必要があります。

Unity上での解決方法は2つあります。
まず一つの解決方法は後からテクスチャを配置する方法です。フォルダを作成し、プロジェクトにテクスチャをインポートします。
f:id:bluebirdofoz:20170729185557j:plain

画像ファイルなら自動的に、画像として関連付けてインポートされます。
テクスチャの参照先として一覧に表示されるようになるため、以下の手順でマテリアルに設定できます。
 1.hololens の取り込んだオブジェクトをクリックする。
 2.MeshRenderer から Albedo の ◎ ボタンを選択する。
 3.表示された SelectTexture ダイアログから取り込んだテクスチャを選択する。
f:id:bluebirdofoz:20170729185750j:plain
以上でテクスチャの設定が行えます。

別のもう一つの解決方法は取り込み時にテクスチャを設定する方法です。
動きを確認するため、一旦取り込んだ.fbxファイルを削除します。先ほど取り込んだテクスチャファイルは削除しないでください。
f:id:bluebirdofoz:20170729185741j:plain

さて、.fbxファイルにはテクスチャファイルは含まれませんが、テクスチャファイルへの参照設定は含まれています。
テキストファイルで.fbxファイルを開くと"hololens_circle_texture.png"という文字が見つかりました。
最初の.fbxファイル取り込み時は、参照先にこのファイルが見つからなかったため、テクスチャが表示されていなかった訳です。

今はUnityプロジェクトに取り込んだテクスチャが画像ファイルの一覧として参照先に設定されています。
この状態で.fbxファイルを改めて取り込みます。
f:id:bluebirdofoz:20170729185805j:plain

今度は.fbxファイルの取り込み時点でテクスチャが貼られました。
二つの解決方法どちらでもUnity内の成果オブジェクトとして違いはありません。(厳密には手順上インスタンスへの設定か否か等の違いがありますが)
ただ.fbxファイルはテクスチャの参照設定だけを保持しているということは覚えておきましょう。
テクスチャが貼られていないという事象は別の3Dツールへの.fbxファイルの持ち込み時にも発生しうるため、焦らずに済むようになります。


次回は「position, rotation, scale といったTransformコンポーネントのデフォルト値が 1 でない」の問題の解決にトライします。
bluebirdofoz.hatenablog.com

Unityアニメーション講座 その4

本日はUnityアニメーションの講座の続きです。
f:id:bluebirdofoz:20170728041154j:plain

作成したプロジェクトに手を加えて、新しいアニメーションの追加にトライします。
bluebirdofoz.hatenablog.com

前回作成したプロジェクトを開きます。
f:id:bluebirdofoz:20170728041233j:plain

最初に、追加するアニメーションの新しい State を作成します。
まずは以下の手順で「UnityChanLocomotions」を開いてください。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブにある Animator コンポーネント内の「UnityChanLocomotions」をダブルクリックする。
 3.画面中央に「UnityChanLocomotions」のフロー図が表示される。
f:id:bluebirdofoz:20170728041241j:plain

フロー図上で右クリックをして、Create State -> Empty を選択します。
f:id:bluebirdofoz:20170728041251j:plain

「New State」という新しい State が作成されます。
f:id:bluebirdofoz:20170728041301j:plain

今回はユニティちゃんの勝利ポーズのアニメーションを作成します。
以下の通り、State の名前とモーションを設定します。
 1.Inspector 上部の名前「Winner」を変更する。
 2.Motion : None(Motion) の右端にある ◎ ボタンをクリックする。
 3.表示されたダイアログから「WIN00」を選択する。
f:id:bluebirdofoz:20170728041312j:plain

Motion に WIN00 が設定されればOKです。前回学んだモーションの確認方法で WIN00 のモーションを確認できます。
f:id:bluebirdofoz:20170728041323j:plain


次に遷移条件の設定のため、「Winner」State へのトリガーとなる新しい Parameters 設定を追加します。
以下の手順で「WinBool」Parameter を作成してください。
 1.Parameters タブの右上にある + ボタンをクリックする。
 2.表示されたメニューから Bool を選択する。
 3.作成された Parameter に「WinBool」という名前を設定する。
f:id:bluebirdofoz:20170728041339j:plain

さて、追加した「WinBool」Parameter を元に Transition を作成し、「Idle」State から「Winner」State へ遷移を設定します。
「Idle」State 上で右クリックをして、Make Transition を選択します。
f:id:bluebirdofoz:20170728041352j:plain

矢印が表示されるので、そのまま「Winner」State をクリックします。
すると「Idle」State から「Winner」State へ矢印線が結ばれます。
f:id:bluebirdofoz:20170728041402j:plain

Transition の設定を行います。作成した矢印線をクリックして Inspector タブを開いてください。
f:id:bluebirdofoz:20170728041415j:plain

まずは以下の手順で Conditions の設定を行い、遷移条件を設定しましょう。
 1.Conditions の右下にある + ボタンをクリックすると、条件式が追加される。
 2.追加された条件を「WinBool : true」の条件で設定する。
f:id:bluebirdofoz:20170728041426j:plain

次に遷移のアニメーションの繋がりを設定します。
そのままの状態で「再生」ボタンを押してアニメーションを確認してみてください。
f:id:bluebirdofoz:20170728041437j:plain
勝利ポーズにすぐに遷移せず、立ちポーズの状態が長く続くアニメーションになっていると思います。

トリガーが発生すれば、すぐにポーズを遷移したいので、アニメーションの繋がりを調整します。
Settings ウィンドウの Winner ブロックを前方に移動させてください。
f:id:bluebirdofoz:20170728041448j:plain

合わせて、Idle ブロックから Winner ブロックへの遷移タイミングを示す青枠についても前方に移動させます。
f:id:bluebirdofoz:20170728041459j:plain

この状態で再び「再生」ボタンを押してアニメーションを確認してみてください。
先ほどと比べ、すぐに勝利ポーズへの遷移が始まることが確認できます。

更にもう一つ、Has Exit Time のチェックを外してください。
f:id:bluebirdofoz:20170728041604j:plain
Has Exit Time が無効の場合、「Idle」State の立ちモーションのアクションを即座にキャンセルして次のモーションに遷移します。
このチェックを外していないと例え、すぐに勝利ポーズへ遷移が始まるアニメーションを設定していても、その前の立ちモーションの完了を待ってしまうため、即座にモーションが遷移しません。


「Idle」State から「Winner」State への遷移が設定できました。しかし、このままだと一度「Winner」State に入ってしまうと「Idle」State に戻ってきません。
「Winner」State から「Idle」State への遷移も設定しておきましょう。
Transition を「Winner」State から「Idle」State に延ばします。
f:id:bluebirdofoz:20170728041653j:plain

「Winner」State から「Idle」State へ Transition の設定項目ですが、こちらは変更は不要です。
Conditions の設定がない場合、無条件で遷移が発生します。
このため、「Idle」State から「Winner」State への遷移が発生すると、その後、必ず「Winner」State から「Idle」State に戻る形となります。
そしてこのとき、「Winner」State から「Idle」State への遷移では Has Exit Time が無効されていないため、「Winner」State のモーションが一通り再生された後、「Idle」State の立ちポーズに戻るという流れになる訳です。


フローの設定はこれで完了です。
後はスクリプトにて、トリガーの発生を実装しましょう。
以下の手順を実施し、スクリプトファイルを開いてください。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブにある UnityChanControlScriptWithRgidBody(Script) コンポーネント内にある
  Script「UnityChanControlScriptWithRgidBody」をダブルクリックする。
f:id:bluebirdofoz:20170728041720j:plain

UnityChanControlScriptWithRgidBody.cs が個別のテキストエディタで開かれます。
Winアニメーション用に修正した UnityChanControlScriptWithRgidBody.cs を以下に添付します。内容を上書きしてください。
・UnityChanControlScriptWithRgidBody.cs

//
// Mecanimのアニメーションデータが、原点で移動しない場合の Rigidbody付きコントローラ
// サンプル
// 2014/03/13 N.Kobyasahi
//
using UnityEngine;
using System.Collections;

namespace UnityChan
{
// 必要なコンポーネントの列記
    [RequireComponent(typeof(Animator))]
    [RequireComponent(typeof(CapsuleCollider))]
    [RequireComponent(typeof(Rigidbody))]

    public class UnityChanControlScriptWithRgidBody : MonoBehaviour
    {

        public float animSpeed = 1.5f;                // アニメーション再生速度設定
        public float lookSmoother = 3.0f;            // a smoothing setting for camera motion
        public bool useCurves = true;                // Mecanimでカーブ調整を使うか設定する
        // このスイッチが入っていないとカーブは使われない
        public float useCurvesHeight = 0.5f;        // カーブ補正の有効高さ(地面をすり抜けやすい時には大きくする)

        // 以下キャラクターコントローラ用パラメタ
        // 前進速度
        public float forwardSpeed = 7.0f;
        // 後退速度
        public float backwardSpeed = 2.0f;
        // 旋回速度
        public float rotateSpeed = 2.0f;
        // ジャンプ威力
        public float jumpPower = 3.0f; 
        // キャラクターコントローラ(カプセルコライダ)の参照
        private CapsuleCollider col;
        private Rigidbody rb;
        // キャラクターコントローラ(カプセルコライダ)の移動量
        private Vector3 velocity;
        // CapsuleColliderで設定されているコライダのHeiht、Centerの初期値を収める変数
        private float orgColHight;
        private Vector3 orgVectColCenter;
        private Animator anim;                            // キャラにアタッチされるアニメーターへの参照
        private AnimatorStateInfo currentBaseState;            // base layerで使われる、アニメーターの現在の状態の参照

        private GameObject cameraObject;    // メインカメラへの参照
        
        // アニメーター各ステートへの参照
        static int idleState = Animator.StringToHash ("Base Layer.Idle");
        static int locoState = Animator.StringToHash ("Base Layer.Locomotion");
        static int jumpState = Animator.StringToHash ("Base Layer.Jump");
        static int restState = Animator.StringToHash ("Base Layer.Rest");

// ++++++++++++++++++++++++++++++++++++ 勝利ポーズの追加 開始 ++++++++++++++++++++++++++++++++++++
        static int winState = Animator.StringToHash("Base Layer.Winner");
// ++++++++++++++++++++++++++++++++++++ 勝利ポーズの追加 終了 ++++++++++++++++++++++++++++++++++++

        // 初期化
        void Start ()
        {
            // Animatorコンポーネントを取得する
            anim = GetComponent<Animator> ();
            // CapsuleColliderコンポーネントを取得する(カプセル型コリジョン)
            col = GetComponent<CapsuleCollider> ();
            rb = GetComponent<Rigidbody> ();
            //メインカメラを取得する
            cameraObject = GameObject.FindWithTag ("MainCamera");
            // CapsuleColliderコンポーネントのHeight、Centerの初期値を保存する
            orgColHight = col.height;
            orgVectColCenter = col.center;
        }
    
    
        // 以下、メイン処理.リジッドボディと絡めるので、FixedUpdate内で処理を行う.
        void FixedUpdate ()
        {
            float h = Input.GetAxis ("Horizontal");                // 入力デバイスの水平軸をhで定義
            float v = Input.GetAxis ("Vertical");                // 入力デバイスの垂直軸をvで定義
            anim.SetFloat ("Speed", v);                            // Animator側で設定している"Speed"パラメタにvを渡す
            anim.SetFloat ("Direction", h);                         // Animator側で設定している"Direction"パラメタにhを渡す
            anim.speed = animSpeed;                                // Animatorのモーション再生速度に animSpeedを設定する
            currentBaseState = anim.GetCurrentAnimatorStateInfo (0);    // 参照用のステート変数にBase Layer (0)の現在のステートを設定する
            rb.useGravity = true;//ジャンプ中に重力を切るので、それ以外は重力の影響を受けるようにする
        
        
        
            // 以下、キャラクターの移動処理
            velocity = new Vector3 (0, 0, v);        // 上下のキー入力からZ軸方向の移動量を取得
            // キャラクターのローカル空間での方向に変換
            velocity = transform.TransformDirection (velocity);
            //以下のvの閾値は、Mecanim側のトランジションと一緒に調整する
            if (v > 0.1) {
                velocity *= forwardSpeed;        // 移動速度を掛ける
            } else if (v < -0.1) {
                velocity *= backwardSpeed;    // 移動速度を掛ける
            }
        
            if (Input.GetButtonDown ("Jump")) {    // スペースキーを入力したら

                //アニメーションのステートがLocomotionの最中のみジャンプできる
                if (currentBaseState.nameHash == locoState) {
                    //ステート遷移中でなかったらジャンプできる
                    if (!anim.IsInTransition (0)) {
                        rb.AddForce (Vector3.up * jumpPower, ForceMode.VelocityChange);
                        anim.SetBool ("Jump", true);        // Animatorにジャンプに切り替えるフラグを送る
                    }
                }
            }
        

            // 上下のキー入力でキャラクターを移動させる
            transform.localPosition += velocity * Time.fixedDeltaTime;

            // 左右のキー入力でキャラクタをY軸で旋回させる
            transform.Rotate (0, h * rotateSpeed, 0);    
    

            // 以下、Animatorの各ステート中での処理
            // Locomotion中
            // 現在のベースレイヤーがlocoStateの時
            if (currentBaseState.nameHash == locoState) {
                //カーブでコライダ調整をしている時は、念のためにリセットする
                if (useCurves) {
                    resetCollider ();
                }
            }
        // JUMP中の処理
        // 現在のベースレイヤーがjumpStateの時
        else if (currentBaseState.nameHash == jumpState) {
                cameraObject.SendMessage ("setCameraPositionJumpView");    // ジャンプ中のカメラに変更
                // ステートがトランジション中でない場合
                if (!anim.IsInTransition (0)) {
                
                    // 以下、カーブ調整をする場合の処理
                    if (useCurves) {
                        // 以下JUMP00アニメーションについているカーブJumpHeightとGravityControl
                        // JumpHeight:JUMP00でのジャンプの高さ(0~1)
                        // GravityControl:1⇒ジャンプ中(重力無効)、0⇒重力有効
                        float jumpHeight = anim.GetFloat ("JumpHeight");
                        float gravityControl = anim.GetFloat ("GravityControl"); 
                        if (gravityControl > 0)
                            rb.useGravity = false;    //ジャンプ中の重力の影響を切る
                                        
                        // レイキャストをキャラクターのセンターから落とす
                        Ray ray = new Ray (transform.position + Vector3.up, -Vector3.up);
                        RaycastHit hitInfo = new RaycastHit ();
                        // 高さが useCurvesHeight 以上ある時のみ、コライダーの高さと中心をJUMP00アニメーションについているカーブで調整する
                        if (Physics.Raycast (ray, out hitInfo)) {
                            if (hitInfo.distance > useCurvesHeight) {
                                col.height = orgColHight - jumpHeight;            // 調整されたコライダーの高さ
                                float adjCenterY = orgVectColCenter.y + jumpHeight;
                                col.center = new Vector3 (0, adjCenterY, 0);    // 調整されたコライダーのセンター
                            } else {
                                // 閾値よりも低い時には初期値に戻す(念のため)                    
                                resetCollider ();
                            }
                        }
                    }
                    // Jump bool値をリセットする(ループしないようにする)                
                    anim.SetBool ("Jump", false);
                }
            }
        // IDLE中の処理
        // 現在のベースレイヤーがidleStateの時
        else if (currentBaseState.nameHash == idleState) {
                //カーブでコライダ調整をしている時は、念のためにリセットする
                if (useCurves) {
                    resetCollider ();
                }
                // スペースキーを入力したらRest状態になる
                if (Input.GetButtonDown ("Jump")) {
                    anim.SetBool ("Rest", true);
                }
// ++++++++++++++++++++++++++++++++++++ 勝利ポーズの追加 開始 ++++++++++++++++++++++++++++++++++++
                // エンターキーを入力したらWin状態になる
                if (Input.GetKey(KeyCode.Return))
                {
                    anim.SetBool("WinBool", true);
                }
// ++++++++++++++++++++++++++++++++++++ 勝利ポーズの追加 開始 ++++++++++++++++++++++++++++++++++++
            }
        // REST中の処理
        // 現在のベースレイヤーがrestStateの時
        else if (currentBaseState.nameHash == restState) {
                //cameraObject.SendMessage("setCameraPositionFrontView");        // カメラを正面に切り替える
                // ステートが遷移中でない場合、Rest bool値をリセットする(ループしないようにする)
                if (!anim.IsInTransition (0)) {
                    anim.SetBool ("Rest", false);
                }
            }
// ++++++++++++++++++++++++++++++++++++ 勝利ポーズの追加 開始 ++++++++++++++++++++++++++++++++++++
        // WIN中の処理
        // 現在のベースレイヤーがwinStateの時
        else if (currentBaseState.nameHash == winState) {
                //cameraObject.SendMessage("setCameraPositionFrontView");        // カメラを正面に切り替える
                // ステートが遷移中でない場合、WinBool bool値をリセットする(ループしないようにする)
                if (!anim.IsInTransition(0))
                {
                    anim.SetBool("WinBool", false);
                }
            }
// ++++++++++++++++++++++++++++++++++++ 勝利ポーズの追加 終了 ++++++++++++++++++++++++++++++++++++
    }

    void OnGUI ()
        {
            GUI.Box (new Rect (Screen.width - 260, 10, 250, 150), "Interaction");
            GUI.Label (new Rect (Screen.width - 245, 30, 250, 30), "Up/Down Arrow : Go Forwald/Go Back");
            GUI.Label (new Rect (Screen.width - 245, 50, 250, 30), "Left/Right Arrow : Turn Left/Turn Right");
            GUI.Label (new Rect (Screen.width - 245, 70, 250, 30), "Hit Space key while Running : Jump");
            GUI.Label (new Rect (Screen.width - 245, 90, 250, 30), "Hit Spase key while Stopping : Rest");
            GUI.Label (new Rect (Screen.width - 245, 110, 250, 30), "Left Control : Front Camera");
            GUI.Label (new Rect (Screen.width - 245, 130, 250, 30), "Alt : LookAt Camera");
        }


        // キャラクターのコライダーサイズのリセット関数
        void resetCollider ()
        {
            // コンポーネントのHeight、Centerの初期値を戻す
            col.height = orgColHight;
            col.center = orgVectColCenter;
        }
    }
}

シーンの「再生」ボタンを押してシーンを開始します。
エンターキーを押してみてください。ユニティちゃんが勝利ポーズを取るアニメーションが始まれば成功です。
f:id:bluebirdofoz:20170728041741j:plain

以上でアニメーションの追加が出来ました。Unityアニメーション講座はここで一旦区切りとします。
ここまでお付き合い頂きありがとうございました。

Unityアニメーション講座 その3

本日はUnityアニメーションの講座の続きです。
f:id:bluebirdofoz:20170728021132j:plain

前回作成したプロジェクトを確認して、アニメーションの仕組みを理解します。
bluebirdofoz.hatenablog.com

前回作成したプロジェクトを開きます。
f:id:bluebirdofoz:20170728021214j:plain

さて前回、何故アニメーションが操作できたかを順を追って理解していきます。
「その1」でユニティちゃんに設定した「UnityChanLocomotions」を改めて確認します。
以下の手順で「UnityChanLocomotions」を開いてください。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブにある Animator コンポーネント内の「UnityChanLocomotions」をダブルクリックする。
 3.画面中央に「UnityChanLocomotions」のフロー図が表示される。
f:id:bluebirdofoz:20170728021223j:plain

フロー図を読み解くために、初めにフロー図の中身について簡単に説明します。
アニメーションのフローには大きく分けて以下の3つの要素が関係します。
 1. Parameters : フロー全体が持つパラメータ (赤枠)
 2. State : アニメーションの設定を持つ (緑枠)
 3. Transition : アニメーションの状態遷移条件を示す (青枠)
f:id:bluebirdofoz:20170728021233j:plain

大雑把に説明しますと、State がアニメーションの設定を定義しており、Parameters の変化が起こると Transition の遷移条件に従って、State から State へとアニメーションの状態が遷移していきます。


まずは各 State にどのようなモーションが割り当てられているかを確認する方法を学びます。
「Idle」State を確認してみましょう。
以下の手順で、State に割り当てられたモーションファイルにアクセスします。
 1.「Idle」Stateをクリックする。
 2.Inpector タブにある Motion に割り当てられた WAIT00 をクリックする。
 3.モーションファイルが存在するフォルダが開きます。
f:id:bluebirdofoz:20170728021359j:plain

次にモーションファイルの内容を確認します。キャプチャに従って手順を進めてください。
 1.WAIT00 ファイルをクリックする。
 2.表示された小ウィンドウの右下にあるアイコンをクリックする。
 3.選択メニューから「Other...」を選択する。
f:id:bluebirdofoz:20170728021407j:plain

 4.表示されたダイアログから「unitychan」を選択する。
 5.小ウィンドウにユニティちゃんが表示されていればOKです。
f:id:bluebirdofoz:20170728021422j:plain

小ウィンドウの「再生」ボタンを押すとアニメーションが再生されます。
f:id:bluebirdofoz:20170728021432j:plain
各 State に割り当てられたモーションはこの手順で確認できます。
モーションを確認する際に用いるモデルは基本的にモーションファイルと関連付いたモデルを選択して用いてください。

同じ手順で「Rest」State を確認してみてください。
前回の記事で実行した、ユニティちゃんが伸びをするアニメーションを確認できます。
f:id:bluebirdofoz:20170728021447j:plain
つまりは前回、スペースキーを押したとき、「Idle」State から「Rest」State への遷移が発生し、ユニティちゃんは立ちポーズから伸びポーズを行ったわけです。


次に各 Transition にどのような遷移条件が割り当てられているかを確認する方法を学びます。
「Idle」State から「Rest」State への遷移条件を確認してみましょう。以下の手順を実施してください。
 1.「Idle」State から「Rest」State への矢印線をクリックする。
  (矢印の向きに注意してください。「Idle」→「Rest」のものをクリックします)
 2.Inpector タブにある Conditions の設定が遷移条件です。
f:id:bluebirdofoz:20170728021501j:plain

「Rest」「true」が設定されていることが分かります。
ここでの「Rest」は Parameters 一覧にある「Rest」を指します。
f:id:bluebirdofoz:20170728021511j:plain
この「Rest」Parameters が true になることが「Idle」State から「Rest」State へ遷移する条件です。


最後に、前回適用した script を確認しましょう。
以下の手順を実施し、スクリプトファイルを開いてください。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブにある UnityChanControlScriptWithRgidBody(Script) コンポーネント内にある
  Script「UnityChanControlScriptWithRgidBody」をダブルクリックする。
f:id:bluebirdofoz:20170728021523j:plain


UnityChanControlScriptWithRgidBody.cs が個別のテキストエディタで開かれます。
158行目~179行目のコードを確認してください。
・UnityChanControlScriptWithRgidBody.cs

    // IDLE中の処理
    // 現在のベースレイヤーがidleStateの時
    else if (currentBaseState.nameHash == idleState) {
        //カーブでコライダ調整をしている時は、念のためにリセットする
        if (useCurves) {
          resetCollider ();
        }
        // スペースキーを入力したらRest状態になる
        if (Input.GetButtonDown ("Jump")) {
          anim.SetBool ("Rest", true);
        }
      }
    // REST中の処理
    // 現在のベースレイヤーがrestStateの時
    else if (currentBaseState.nameHash == restState) {
        //cameraObject.SendMessage("setCameraPositionFrontView");    // カメラを正面に切り替える
        // ステートが遷移中でない場合、Rest bool値をリセットする(ループしないようにする)
        if (!anim.IsInTransition (0)) {
          anim.SetBool ("Rest", false);
        }
      }
    }

167行目、176行目の以下のコードが「Rest」Parameters の変更箇所になります。
・anim.SetBool ("Rest", true);
・anim.SetBool ("Rest", false);

「Idle」State のとき、スクリプトがスペースキーを入力をキャッチすると、「Rest」Parameters を true に変更するため、ゲーム中でスペースキーを押すと、ユニティちゃんが伸びポーズを行ったという訳です。
「Rest」Parameters が true のままだと、「Idle」State から「Rest」State へ遷移が繰り返されてしまうため、「Rest」State に入れば「Rest」Parameters を false に変更しています。

以上です。今回でアニメーションのフローの仕組みについて理解できました。
次回は今回の学習内容を用いて新しいアニメーションの設定を行います。
bluebirdofoz.hatenablog.com


余談。
コード中にある Input.GetButtonDown ("Jump") というコードに首を傾げた人もいるかと思います。
"Jump"ボタン =(イコール) スペースキーの関連付けは InputManager に設定されています。
以下の手順で確認可能です。
 1.Edit メニューから Project Settings -> Input を選択する。
 2.表示された InputManager の中に Jump の設定がある。
 3.PositiveButton の設定でスペースキーが割り当てられている。
f:id:bluebirdofoz:20170728021538j:plain

Unityアニメーション講座 その2

本日はUnityアニメーションの講座の続きです。
f:id:bluebirdofoz:20170727024413j:plain

前回作成したプロジェクトに手を加えて、今度はキャラクタをアニメーションと共に操作してみます。
bluebirdofoz.hatenablog.com

前回作成したプロジェクトを開きます。
f:id:bluebirdofoz:20170727024435j:plain

初めに、ユニティちゃんがシーン内を走り回れるようシーンの準備を行います
まずは床を作成します。以下の手順でシーンに床を作成してください。
 1.Hierarchy 内で右クリックする。
 2.メニューから 3D Object -> Plane を選択する。
f:id:bluebirdofoz:20170727024445j:plain

以下のように、シーンに床が作成されます。
f:id:bluebirdofoz:20170727024455j:plain

次にユニティちゃんが床に立てるよう、ユニティちゃんに重力とアタリ判定を設定します。

まずは重力の設定です。
以下の手順で unitychan オブジェクトに Rigidbody コンポーネントを適用します。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブの最下部にある Add Component をクリックする。
 3.「Rigidbody」を検索して、見つかったコンポーネントを選択する。
f:id:bluebirdofoz:20170727024506j:plain

以下のように Rigidbody コンポーネントが追加されます。
f:id:bluebirdofoz:20170727024514j:plain

ただし、このままだとユニティちゃんは重力に従って倒れ込んでしまいます。
以下のように Rigidbody の設定項目を変更します。これにより軸方向の回転が固定され、ユニティちゃんが転倒しなくなります。
Rigidbody
 Constrains
  FreezeRotatin X Y Z 全てチェック
f:id:bluebirdofoz:20170727024530j:plain

次に床とのアタリ判定の設定です。
以下の手順で unitychan オブジェクトに CapsuleCollider コンポーネントを適用します。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブの最下部にある Add Component をクリックする。
 3.「Capsule Collider」を検索して、見つかったコンポーネントを選択する。
f:id:bluebirdofoz:20170727024543j:plain

以下のように CapsuleCollider コンポーネントが追加されます。
f:id:bluebirdofoz:20170727024554j:plain

初期状態の CapsuleCollider コンポーネントはユニティちゃんの足元に球体の形で追加されます。
これではユニティちゃんのアタリ判定として正しい動作をしません。
以下のように値を変更し、ユニティちゃんを包むような形にアタリ判定を修正します。
Capsule Collider
 Center X 0 Y 0.8 Z 0
 Radius 0.3
 Height 1.6
 Direction Y-Axis
f:id:bluebirdofoz:20170727024605j:plain

余談。
感の良い方はこのとき「床側のアタリ判定の設定は?」と考えるかもしれません。
床側のアタリ判定は Plane オブジェクトを追加した際、デフォルトで Mesh Collider コンポーネントが適用されています。
f:id:bluebirdofoz:20170727024630j:plain
この床の Mesh Collider と、ユニティちゃんの Capsule Collider が干渉することでユニティちゃんは床の上に立てる訳です。

さて、この時点で一旦、設定が正常に行えているか動作を確認します。
シーンの「再生」ボタンを押してみてください。床の上にユニティちゃんが立った状態になっていれば成功です。
f:id:bluebirdofoz:20170727024615j:plain
このとき、スペースキーを押してみてください。
特に何も起こりませんか?結構です。
最後にキーを押すとアニメーションをキックするスクリプトを追加しましょう。


ユニティちゃんの動きをコントロールするスクリプトを適用します。
以下の手順で unitychan オブジェクトに UnityChanControlScriptWithRgidBody コンポーネントを適用します。
 1.unitychan オブジェクトを選択する。
 2.Inpector タブの最下部にある Add Component をクリックする。
 3.「UnityChanControlScriptWithRgidBody」を検索して、見つかったコンポーネントを選択する。
f:id:bluebirdofoz:20170727024644j:plain

シーンの「再生」ボタンを押してみてください。
操作方法に関するパネルが表示されるようになっていれば適用されています。
f:id:bluebirdofoz:20170727024656j:plain

その状態で、スペースキーを押してみてください。ユニティちゃんが伸びをするアニメーションが始まります。
f:id:bluebirdofoz:20170727024708j:plain
他にも矢印キーの↑キーを押せば前進移動を行い、↓キーを押せば後退移動を行います。

スクリプトの適用により、キャラクタのアニメーションを操作できることが確認できました。
次回は追加したスクリプトの中身を確認し、アニメーションの仕組みを理解します。
bluebirdofoz.hatenablog.com

Unityアニメーション講座 その1

さて、本日はUnityアニメーションの講座です。
本講座ではユニティちゃんパッケージを利用して、キャラクタへのアニメーション設定を学びます。
f:id:bluebirdofoz:20170726004638j:plain

以下のソフトのインストールとパッケージの取得が前提となります。

・Unity 5.6 以上のインストー
unity3d.com
 上記サイトから プラン選択&ダウンロード -> Personalを試す でインストーラを取得する。
 - UnityDownloadAssistant-2017.1.0f3.exe
 Unityのインストール手順については別途参照ください。

・ユニティちゃんパッケージ 1.2.1 以上の取得
unity-chan.com
 上記サイトから DATA DOWNLOAD -> ユニティちゃん 3Dモデルデータ で以下のパッケージを取得する。
 - UnityChan_1_2_1.unitypackage

では早速、Unityのテスト用プロジェクトを作成します。
Unityを起動したら以下の手順を実施して、新規プロジェクトを作成してください。
 1.NEWアイコンを選択する。
 2.ProjectNameを命名する。
 3.プロジェクトの保存フォルダを指定する。
 4.CreateProjectでプロジェクトを作成する。
f:id:bluebirdofoz:20170726004742j:plain

プロジェクトが作成されると、以下の画面が表示されます。
f:id:bluebirdofoz:20170726004754j:plain

Unityのプロジェクトを開いた状態で、取得したユニティちゃんパッケージ(UnityChan_1_2_1.unitypackage)をダブルクリックします。
すると、以下のウィンドウが開きますので、そのまま「import」ボタンをクリックします。
f:id:bluebirdofoz:20170726004927j:plain

インポートが完了すると、以下の通り、Assetsにユニティちゃんパッケージが読み込まれます。
f:id:bluebirdofoz:20170726004937j:plain

ここで、いつでも作業が中断できるようプロジェクトの保存を行っておきます。
まず現在作成中のシーン情報を保存します。メニューから File -> Save Scene を選択します。
f:id:bluebirdofoz:20170726005000j:plain

初回保存時には Scene ファイルの保存場所の指定が必要なので、今回は以下の設定で保存しました。
 1.AssetsフォルダにSceneフォルダを作成する。
 2.ファイル名を MainScene とする。
 3.保存する
f:id:bluebirdofoz:20170726005009j:plain

すると以下の通り、Assets配下に Scene フォルダが作成され、MainScene ファイルが保存されます。
f:id:bluebirdofoz:20170726005018j:plain

次にプロジェクト全体の保存を行います。メニューから File -> Save Scene を選択します。
f:id:bluebirdofoz:20170726005028j:plain
これでプロジェクトの保存は完了です。


今回はユニティちゃんを使って、アニメーションの設定を学んでいきます。
以下の手順を実施して、ユニティちゃんをシーンに取り込みます。
 1.Assets フォルダから UnityChan -> Prefabs を開く。
 2.unitychan.prefab を Hierarchy にドラッグする。
f:id:bluebirdofoz:20170726005047j:plain

すると、以下のように unitychan オブジェクトが Hierarchy に取り込まれ、シーン内にユニティちゃんが出現します。
f:id:bluebirdofoz:20170726005059j:plain

早速ですが、ユニティちゃんにアニメーション設定を行います。
以下の手順を実行して、unitychan オブジェクトの Inspector タブを開いてください。
 1.unitychan オブジェクトを選択する。
 2.Inspector タブをクリックする。
 3.Animator コンポーネントがアタッチされていることを確認する。
f:id:bluebirdofoz:20170726005129j:plain

Unityには複数のアニメーションの設定方法がありますが、今回は「Mecanim」という方法を用います。
「Mecanim」の特徴について興味がある方は以下を参照してみてください。
qiita.com

ユニティちゃんパッケージには予め、この「Mecanim」の機能を利用したアニメーションコントローラが提供されています。
まずはこのアニメーションコントローラを設定します。以下の手順を実行してください。
 1.Animato rコンポーネントの Controller の右端にある「◎」ボタンをクリックする。
 2.コントローラ選択ウィンドウが表示される。
 3.「UnityChanLocomotions」を選択する。
f:id:bluebirdofoz:20170726005158j:plain

Animator コンポーネントの Controller が「UnityChanLocomotions」に設定されていることを確認します。
f:id:bluebirdofoz:20170726010733j:plain

この状態で Animator タブを選択すると、現在ユニティちゃんに設定されているアニメーションのフロー図が確認できます。
f:id:bluebirdofoz:20170726005235j:plain

この状態でシーンを動かすとどうなるか見てみることにします。
まず、ユニティちゃんがよく見えるよう、以下の手順でカメラ位置を移動します。
 1.MainCamera オブジェクトを選択する。
 2.Transform コンポーネントを以下の通り設定する。
   Positon X 0 Y 1 Z -1
   Rotation X 0 Y 0 Z 0
   Scale X 1 Y 1 Z 1
 3.設定が反映されると、CameraPreview の映像が変化します。
f:id:bluebirdofoz:20170726005323j:plain

次にユニティちゃんがカメラの方向を向くよう、以下の手順でユニティちゃんを方向転換します。
また、今回は IdleChanger と FaceUpdate の機能は利用しないので、ここで無効化しておきます。
 1.unitychan オブジェクトを選択する。
 2.Transform コンポーネントを以下の通り設定する。
   Positon X 0 Y 0 Z 0
   Rotation X 0 Y 180 Z 0
   Scale X 1 Y 1 Z 1
 3.IdleChanger(Script) コンポーネントのチェックを外す。
 4.FaceUpdate(Script) コンポーネントのチェックを外す。
f:id:bluebirdofoz:20170726010013j:plain

シーンを再生します。「再生」ボタンをクリックします。
ゲームタブが開かれて、こちらを向いたユニティちゃんが表示されれば成功です。
f:id:bluebirdofoz:20170726010027j:plain


さて、このとき、ユニティちゃんはシーンタブで表示されていた「手を広げたポーズ」ではなく、「手を下したポーズ」で再生されるはずです。

これはアニメーションコントローラとして設定した「UnityChanLocomotions」のデフォルトの遷移先が「Idle」状態だからです。
f:id:bluebirdofoz:20170726010056j:plain
「Idle」の状態には「WAIT00」という「手を下したポーズ」のモーションが設定されており、この状態に遷移したため、ユニティちゃんはゲーム開始と共に「手を下したポーズ」をとったという訳です。

これでまずはアニメーションの設定と動作について確認できました。
次回はアニメーションの遷移について学習していきます。
bluebirdofoz.hatenablog.com