Unityでオリキャラのモーションテスト
Unity



さて、Blenderで作り上げたオリキャラをUnityにFBXでインポートしてみた図です。Unity 2017使ってみました。




そろそろ、このキャラクターの名前を決定しておくことにしました。

その名も『桃実沢まい』。小柄で華奢な割にはけっこう力持ち、チャレンジ精神が旺盛で身体能力も並外れているところから、周りからは「Mighty」をもじって「まいティーちゃん」と呼ばれている、という感じで。(^^;)




シェーダーは「ユニティちゃんトゥーンシェーダー2.0」を使ってます。今回は、前髪に隠れている眉を透けて見えるようにしてみました。ただ、眉と髪が同じ色だと境目が分からなくなってしまうので、より効果的にするために眉のテクスチャに輪郭線を描き足しました。




設定の仕方は、隠れているもの(眉)のシェーダーを「StenciMask系」に、透かして見せるもの(前髪)のシェーダーを「StenciOut系」にすると言う具合です。




「ユニティちゃんトゥーンシェーダー2.0」ではポリゴンの片面表示と両面表示の設定が出来るようになってます。デフォルトで「BACK」になっていてスカートの裏側が黒かったのですが「Cull Mode」をOFFにすると両面表示になりました。




Blenderでモデルを作ってモーションを付けてもUnity上でどう動いて見えるかは実際にUnityで動かしてみないと分かりません。それで、まいティーちゃんにBlenderでいくつかアニメーションを作ってUnityで動作チェックしてみました。


今回もImgurのGIF動画にしてみました。

元のYouTube動画はこちら
https://youtu.be/kiVnTLmzjUc


前に作った動画の画質が悪くてどうしたものかと思っていたらブラウザにもよるみたいですね。普段IE11を使っているのですが、Chromeで見てみたら普通に綺麗でした。なんででしょう?

あと、読み込みに失敗して右側が隠れてしまうこともあるようです、原因はよく分かりませんがその際はご了承下さい。




一応、モーションの解説的なものを。まず、「待機」です。ここから各モーションへ分岐するということに。

キーボードのキーにも各モーションを割り当てていたのですが、動画的にUIボタンも付けてみました。「走る」と「ピース」はボタンを押したら3秒間モーションを再生するとしてみました。




「走る」です。今まで走るモーションはいろいろなソフトでチャレンジしましたがかなり苦戦したものです。意外にもBlenderが一番付けやすかったですね。Blenderだとボーンコンストレイントを簡単に設定できるので今後はモデリングだけではなくモーション付けにも大いに役立ってくれそうです。

髪やスカート等の揺れモノは今回も「Unity揺れものスクリプト」を使わせてもらってます。リボンの動きがちょっとコミカルで面白いですね。やはり、手付けではこんなに自然な動きは付けられません。

ただ、難航したのはUnity上でのスカートの挙動です。結局、かなり試行錯誤と修正が必要でした。これについてはまたの機会に。




「がんばるぞい!」。ではなく、「よし!」です。(笑)




「おー!」。本当は「やったー!」のつもりでしたが思っていたよりモーションが短かったので「おー!」に変更しました。(^^;)

髪用として左右の肩にコリダーを付けていますが、左腕を上げたとき髪が貫通しないように左腕にさらに2つコリダーを追加してあります。うまくいったようです。




「ピース」。実際にピースする時は薬指と小指はぎっちり握ってないんですよね。あと、腰に手を当てるときは腰骨の手を置く方が少し上がるのが自然です。これらも作った後に気がついて修正です。




「ユニティちゃんトゥーンシェーダー」だとリアルタイムでのベタ塗りの影がいい感じですね。逆光の演出も使えそうです。




せっかくなので、「走る」の別角度を「うごイラ」にしてみました。


スポンサーサイト
テーマ: CG ジャンル: 日記
表情をスクリプトで滑らかに遷移
Unity



前回、Unity上でスクリプトからBlendShapesを操作して中割り無しでキャラの表情を変えることをやってみましたが、今回はスクリプトから表情を滑らかに遷移させるということをやってみたいと思います。

Unityでは、ある値からある値へと徐々に近づかせる手段としてMathfクラスのLerp関数とMoveTowards関数を使う方法があると思います。とりあえず、Mathf.MoveTowardsとコルーチンを使ってそれっぽい動きになるようにしてみました。

動画にしてみました。

https://youtu.be/beKhRQ-W4-Q


このキャラは、Blenderのみで作っているオリキャラです。半年前にボーンとモーフを入れてあったのですが、なかなかそちらに時間が回せず衣装をまだ考えてなく放置したままでした。今回、表情テストモデルとして登場させてみました。

シェーダーには「ユニティちゃんトゥーンシェーダー2.0」を使ってみました。しかし、Youtubeにアップした動画をImgurでgifにして貼ってみたのですが驚くほど画質がよくありませんねぇ(汗)。一応、表情がなめらかに変化しているのは伝わりますでしょうか。(リンク先は大きくてキレイな画質ですので)

スクリプトはこのような感じです。

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class FacialMorphingScript : MonoBehaviour {

    SkinnedMeshRenderer SKMR_head;
    Transform head;
    public Text eye, mouth;
    float we, wm = 0;

    void Awake() {
        head = transform.FindChild("Head");
    }

    void Start () {
        SKMR_head = head.GetComponent<SkinnedMeshRenderer>();
    }

    public void OnEyesButton() {
        if (we == 0) {
            StartCoroutine(EyeClose());
        } else
        if (we == 100) {
            StartCoroutine(EyeOpen());
        }
    }
    public void OnMouthButton() {
        if (wm == 0) {
            StartCoroutine(MouthOpen());
        } else
        if (wm == 100) {
            StartCoroutine(MouthClose());
        }
    }

    IEnumerator EyeClose() {
        for (int i = 0; i <= 100; i += 10) {
            we = Mathf.MoveTowards(0, 100, i);
            SKMR_head.SetBlendShapeWeight(3, we);//目「笑顔」閉じる
            eye.text = we.ToString();
            yield return new WaitForSeconds(0.02f);
        }
    }
    IEnumerator EyeOpen() {
        for (int i = 100; i >= 0; i -= 10) {
            we = Mathf.MoveTowards(0, 100, i);
            SKMR_head.SetBlendShapeWeight(3, we);//目「笑顔」開く
            eye.text = we.ToString();
            yield return new WaitForSeconds(0.02f);
        }
    }
    IEnumerator MouthOpen() {
        for (int i = 0; i <= 100; i += 10) {
            wm = Mathf.MoveTowards(0, 100, i);
            SKMR_head.SetBlendShapeWeight(10, wm);//口「あ」開く
            mouth.text = wm.ToString();
            yield return new WaitForSeconds(0.02f);
        }
    }
    IEnumerator MouthClose() {
        for (int i = 100; i >= 0; i -= 10) {
            wm = Mathf.MoveTowards(0, 100, i);
            SKMR_head.SetBlendShapeWeight(10, wm);//口「あ」閉じる
            mouth.text = wm.ToString();
            yield return new WaitForSeconds(0.02f);
        }
    }
}


目が完全に開いている時に「目ボタン」を押すと目を閉じ、完全に閉じている時に「目ボタン」を押すと開く。口が完全に閉じている時に「口ボタン」を押すと開いて、完全に開いている時に「口ボタン」を押すと閉じる。「両方ボタン」を押すと両方同時に押すのと同じ、という風にしてみました。

コルーチンを使うとアニメーションクリップを扱うような感覚でわかりやすく扱いやすくなりますね。アニメーションのスピードも調整しやすくなります。BlendShapeの値は0から100までの値を10づつで増減させています。手描きのアニメーションでは目の中割りは通常は1~3枚ぐらいだと思うので8フレームもあれば十分ですね。

(ちなみに、コルーチンを使わない関数にすると、for文の処理が終わるまでしばらく待った後で表情が中割り無しでいきなり変わる事になります。)

はじめはMathf.Lerpを使ってみたのですが、目的値に近づいていってもきっちりその値にならなかったり、たどり着く時間も不明瞭な感じで、きっちり正確な数字で管理するのには向いていない気がしました。

Mathf.Lerpは目的値にだんだんゆっくりたどり着くカーブ的な動きをするのなら、Mathf.MoveTowardsは一定速度で目的値に近づけさせる直線的な動きで、今回のやり方に都合が良かったです。

(線形補間はQuaternion.Slerpなどのようにオブジェクトをゆっくりこっちの方に向かせたいような使い方をしたい(厳密な値でなくても良い)時にはいい感じで動いてくれるのですが)

スクリプトからBlendShapesを操作する方法は、会話や歌うときなどリアルタイムで正確に口パクさせたいときなど結構使えるのかもしれないと前回とは違う感想を持ちました。

今回使ってみた「ユニティちゃんトゥーンシェーダー2.0」は映像用向けとして輪郭線や影の扱いが色々細かく設定が出来るようです。やっぱり、標準のトゥーンシェーダーよりクオリティーが上がる気がします。これは使いこなしたいところですね。




せっかくなので、本来のキレイな画質の静止画も載せておきます。

ところで、ユニティちゃんアセット利用でのキャラクターではなくスクリプトやシェーダーのデータのみの使用についてですが、自分的に曖昧だったので確認してみました。

トゥーンシェーダー版のユニティちゃんはUCL2.0で、キャラクターデータを含まない「ユニティちゃんトゥーンシェーダー」のシェーダーコード自体は「アセットストア利用規約およびエンドユーザーライセンス契約」で利用可能です!
’http://unity-chan.com/contents/news/unity-chan-toonshader/’より

とのことです。ユニティちゃんシェーダーのみならライセンス表示はしなくても良いみたいですね。


関連リンク:

Unityでキャラの表情コントロール

Unityでキャラの表情コントロール2

表情をスクリプトで滑らかに遷移

テーマ: CG ジャンル: 日記
Unityでキャラの表情コントロール2
Unity



Blenderで作ったシェイプキー付きのフィギュアをFBXでUnityにインポートするとメッシュごとにインスペクター上の「Skinned Mesh Renderer」の「BlendShapes」で操作できるようになっています。




カレンの顔には29個の表情シェイプキーが付けてあります。あと、眉毛に8個、目に5個、その他に汗や赤面等が12個ほど付けてあります。




モーフのブレンド値は3Dソフトでは一般的に0が最小値で1.0が最大値だと思いますが、Unityでは100が最大値となります。はじめ、1にしても変化したように見えなくて焦りました。

表情アニメーションをUnity上から付ける方法は2つあります。新規にアニメーションクリップを作って「Animation」でキーフレームを打ってさせる方法。もう一つは、スクリプトからBlendShapesを操作する方法です。

しかし、最初スクリプトから動かそうとしてもうまくいきませんでした。「Animation」でキーフレームを打ってさせる方法は重ねたいアニメーションにレイヤーで重ねればよいのですが、スクリプトからでは元のアニメーションのキーフレームの方が優先されるらしく反応してくれませんでした。(スクリプトからレイヤーのようなものを作ってブレンドさせる方法があるのかまでは分かりません)

手っ取り早い解決方法は、元のアニメーションの表情のキーフレームを削除してしまうことです。しかし、FBXでインポートしたアニメーションはデフォルトでは(Read-Only)となっていてキーフレームの削除どころか編集できないようになっています。




こういう時は、FBXのアニメーションクリップを複製(Ctrl + D)してそちらを使用すれば編集可能になります。




とりあえず、シェイプキーのキーフレームを全部削除しておきます。


public class FacialMorphing2 : MonoBehaviour {

    private SkinnedMeshRenderer SKMR_Kao;
    private SkinnedMeshRenderer SKMR_Mayu;  
    private SkinnedMeshRenderer SKMR_me;
    private SkinnedMeshRenderer SKMR_other1;  
    private SkinnedMeshRenderer SKMR_other2;

    private Transform kao;
    private Transform mayu;
    private Transform me;
    private Transform other1;
    private Transform other2;

    public Mesh kaoMesh;

    private int shape_me;
    private int shape_kuti;
    private int shape_mayu;

    void Awake() {
        kao = transform.FindChild("kao");
        mayu = transform.FindChild("mayu");
        me = transform.FindChild("me");
        other1 = transform.FindChild("other1");
        other2 = transform.FindChild("other2");
    }

    void Start() {
        SKMR_Kao = kao.GetComponent<SkinnedMeshRenderer>();
        SKMR_Mayu = mayu.GetComponent<SkinnedMeshRenderer>();
        SKMR_other1 = other1.GetComponent<SkinnedMeshRenderer>();
        SKMR_other2 = other2.GetComponent<SkinnedMeshRenderer>();
    }
...


あとは、各メッシュのSkinnedMeshRendererコンポーネントを取得し各BlendShapesの値を操作します。各メッシュそれぞれにスクリプトをアタッチするとモーフミキシングがバラバラになりやりにくくなるので親元から子のメッシュを取得するようにしました。

FindChildで取得する数が増えると処理が重くなることを想定して、明確にStart()の前に実行されるAwake()を使っています。(FindChildって公式リファレンスに載ってないのですがあんまり使うべきではないのでしょうかね。publicで直接取得でも良かったと思いつつ。)


        shape_mayu = 6;
        shape_me = kaoMesh.GetBlendShapeIndex("ジト目");
        shape_kuti = kaoMesh.GetBlendShapeIndex("たじろぎ_歯無し");

        SKMR_Mayu.SetBlendShapeWeight(shape_mayu, 100);
        SKMR_Kao.SetBlendShapeWeight(shape_me, 56);
        SKMR_Kao.SetBlendShapeWeight(shape_kuti, 100);

BlendShapesのブレンド値には
SkinnedMeshRenderer.SetBlendShapeWeightを使います。引数1はint型でブレンドシェープのインデックス番号で引数2がfloat値のブレンド具合です(リファンレスではウェイトは [0から100] の範囲に制限されないそうです)。

ブレンドシェープの数がひと目で分かるぐらいならインデックス番号でいいんですが、30、40ぐらいになってくるといちいち数えるのが大変になります。

こういう時、Mesh.GetBlendShapeIndexを使えばブレンドシェープに登録されてある名前の文字列からint型のインデックス値を返してくれます。日本語名でも使えるのでこちらの方が見分けやすいですね。ただし、対象のメッシュを予めMesh型で取得しておく必要があります。




スクリプトからBlendShapesを操作して表情を変えさせてみたものをbxSliderを使ってGIFアニメ風に再現してみました。(今回は動かす必要も無いと思い直立不動で表情のみ変化させています)

スクリプトのみで表情を動かすためには次の表情の前に表情を戻す処理や滑らかに遷移させるための処理を考える必要があったりと、やはりスクリプトだけでやるよりはAnimationを使った方が楽だと思いました。

あえて、スクリプトでBlendShapesを操作してアニメーションをさせるならリニアカーブ的に中割り無しで表情を切り替えるような演出をしたい時には使えるかなとかとも思いました。

Unity5.6にしてよく落ちるようになったという話ですが、Unity5.6で新規でプロジェクトを作ったものに関しては落ちることはまだありません。古いバージョンのプロジェクトを扱う時に注意しておけば安心のようです。


関連リンク:

Unityでキャラの表情コントロール

Unityでキャラの表情コントロール2

表情をスクリプトで滑らかに遷移

テーマ: CG ジャンル: 日記
Unityでキャラの表情コントロール
Unity



カレンは表情モーフも作ってあるので、ならばUnity上からでも表情を操作できるようにしたい、ということでやってみることにしました。

まず、Blenderから表情のアニメーションをFBXでUnityに渡せるようにするところからです。




Blenderでは単体のモーションクリップを「アクション」と言うかたちで管理します。その「アクション」を「NLAエディタ」上で複数ブレンドして新たなモーションを作ることも出来ます。「NLAエディタ」ではシェイプキーによる表情も「アクション」に合成させることも出来ます。

表情が不要なら単体「アクション」だけでいいのですが、表情も必要な時は「NLAエディタ」での編集が必要になります。

シェイプキーのみのアニメーションはFBXでUnityに持っていくことは出来ないようで、表情をFBXに入れたい時はフィギュアのアーマチュア(ボーン)のアニメーションと重ねておく必要があります。(必ずしも動かさなくてもよい)

ですので、「T-Pose」に「まばたき」と「眉怒り」と「あ(歯あり)」の表情を付けてFBXでUnityに渡し、Unity側でアニメーションクリップの分割をしてそれぞれの表情を切り出す方法でいきたいと思います。




「T-Pose」からそれぞれの表情を切り出しました。これらの表情にはT-Poseのキーフレームが打たれていますのでモーションの妨げにならないように必要ないところはマスキングしておきます。




このモデルは剣のボーンの扱いをちょっと試す必要があるため、今のところRigは「Humanoid」ではなく「Generic」のままです。ですので、マスクは「アバターマスク」ではなく「Transform」からかけることにします。表情に関係していないところはチェックを外します。




切り出したクリップをAnimatorのLayerにセットします。それぞれの遷移はBool型でスクリプト上から操作します。レイヤーのブレンドは眉は「OverRide」、まぶたと口は「Additive」です。




まず、「まばたき」は自動でするようにしたいのでコルーチンを使うことにします。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class FacialMorphing : MonoBehaviour {
  private bool mayu_ikari = false;
  public Slider mouth_a;
  public Text mabataki_ib;
  private Animator animator;

void Start () {
  animator = GetComponent<Animator>();
  StartCoroutine("MabatakiCor");
}

private IEnumerator MabatakiCor() {
  for (;;) {
      float rand = Random.Range(0.5f, 3.0f);
      mabataki_ib.text = rand.ToString();
      Mabataki();
      yield return new WaitForSeconds(rand);
  }
}

private void Mabataki() {
  animator.SetBool("mabataki", true);
  Invoke("Mabataki0", 0.3f*Time.deltaTime);
}
private void Mabataki0() {
  animator.SetBool("mabataki", false);
}

「まばたき」は一定時間で繰り返しても味気ないので不定期になるようにWaitForSeconds()の引数をRandom.Rangeでランダムに0.5から3.0の間の値になるようにしました。

「まばたき」のクリップは閉じるのと開くのを別々のクリップにしたので閉じたら時間差で開くアニメーションを実行するようにしています。

public void MayuIkariOn() {
  if (!mayu_ikari) {
      animator.SetBool("mayu_ikari", true);
      mayu_ikari = true;
  } else
  if (mayu_ikari) {
      animator.SetBool("mayu_ikari", false);
      mayu_ikari = false;
  }
}

眉毛はUIのボタンを押すたびに「普通」と「怒り」を交互させるようにしました。

口はレイヤーのWeightをスライダーでコントロールして制御してみようと思いました。




public void MouthA3_Slider() {
  float slwma = mouth_a.value;
  animator.SetLayerWeight(3, slwma);
}

レイヤーのWeight値のコントロールにはAnimator.SetLayerWeightを使います。引数1はint型のレイヤーの番号で、引数2は0から1間のFloat値でレイヤーのブレンド具合になります。

それで完成したのをGIFアニメーションにしてみました。


Imgur.comの動画をGIFのようにブログ等に貼れる用に出来るサービスを使ってみました。GIFより軽くてキレイに使えるメリットがある反面、ブラウザ上でピッタリと動画のループを合わせるのは至難の業ですね(汗)。けっこう、格闘しましたが妥協することにします(- -)。なんか再生速度もおかしくなってる気もしますが、いちおう自動まばたきとUIから表情を操作している雰囲気は伝わりますでしょうか(^^;)。(始めに用意したGIFアニメはFC2BLOGのアップロード2BM以内の制限に余裕で超過でした)

とりあえず、Unityでモーフを操作して表情を変えることが出来るようになりました。しかし、こういう感じで作ったモーフをUIから全て操作出来るようにするのはすごく骨が折れそうな作業になりそうですね。さすがに全部はやる気はありませんけど(^^;)。始めからモーションに表情をベイクしておく方が楽ですからね。要所要所で使い分けた方が良さそうですね。

ところで、Unity5.4からUnity5.6にしてみたのですが、Unityがなんかすごい頻度で落ちてしまいます。今まで、こんなに落ちたこともなかったのですが。Unity5.4以前で作ったプロジェクトを扱っていたからかもしれませんが、ちょっと怖いですね。うっかり、残そうと思っていたUnity5.4を上書きインストールしてしまいました。しかし、また入れ直す気にはなれませんので、もう少し様子をみることにしましょう。


~後日追記~

Blenderで作ったシェイプキーはFBXでUnityにインポートするとメッシュごとに「Skinned Mesh Renderer」の「BlendShapes」というかたちでUnity上から全てのモーフが使えるようになっているのを後から知りました。そのことについては次回に書いてみたいと思います。


関連リンク:

Unityでキャラの表情コントロール

Unityでキャラの表情コントロール2

表情をスクリプトで滑らかに遷移

Unityで揺れモノの表現
Unity



今回はUnityでMMDモデルではなく、FBXモデルでオリキャラの揺れモノの物理セットアップをしてみようと思います。




揺れモノですので、何かモーションが必要になります。今回はカレンにBlenderで歩行モーションを付けてみました。




Blenderからアニメーション付きのFBXでエクスポートして、Unityにインポートしました。トゥーンマテリアルは前のを流用しています。

・Unityでのトゥーンセットアップ




今回は、スカートというか腰巻の部分はUnityのクロスシミュレーションを使ってみたいと思います。腰巻のメッシュにPhysicsのClothコンポーネントを追加します。




クロスのEditモードで矩形選択、ペイント等を使いクロスのコンストレイントの影響範囲を設定します。赤が影響力0、緑が影響力Maxになります。クロスが他のメッシュと接触している部分は影響力0にしておかないとずり落ちてしまいます。




クロスの当たり判定のコリダーにはGameObjectのカプセルと球を使います。足にはカプセル、腰には球を設置しました。これらのコリダーだけ必要なので、形状は見えないようにMeshRenderはオフにしておきます。




後は、コリダーを各ボーンの入れ子にしてコリダーの配列にセットします。(球コリダーが一つの場合、Sphere Collidersの2番目はべつにnullのままでいいみたいです)

髪の揺れモノはこちらで配布されている「Unity揺れものスクリプト」を使わせてもらいました。3つのスクリプトを使ってセットアップしていきます。

使い方は、まずルートボーンにスクリプト「YureManager.cs」をアタッチします。




次に、揺らしたいボーンに「YureBone.cs」をアタッチして子ボーンを指定。後は、コリダーにしたいオブジェクトに「YureCollider.cs」をアタッチと、とくに難しい設定無しで揺れモノ表現することができました。




剣と羽のところもこのスクリプトで揺れるようにしました。




GIF動画にしてみました(GIFなので色合いが変わってしまいましたが)。揺れモノの動きは結構いい感じになっていてくれていると思います。設定はコリダーの半径ぐらいしか変更していません。シンプルなのに効果は絶大ですね。

せっかくなので、クロスの各項目の設定で見た目に大きく反映されそうなことをメモしておこうと思います。

「Stretching Stiffness(布の伸縮率)」
「Bending Stiffness(布の曲げ剛性)」
「Damping(モーションの減衰係数)」

上の3つに絞って比較してみたいと思います。




今回のセッティングは「Stretching Stiffness」、「Bending Stiffness」が共に1。「Damping」が0.5です。




「Stretching Stiffness」を0にするとクロスが縮み上がります。




「Bending Stiffness」を0にすると重力に従ったようにだらんと垂れる感じになります。よりリアルな布の感じになりますね。しかし、内側に黒いノイズが頻繁に現れます。ローポリ形状ではちょっとキビしいのかもしれません。(トゥーンシェーダーで両面表示だからというのもあるのかもしれませんが)

布であっても垂れずにモデリングした形状をなるべく保ってほしい時にはここの値は大きい方がいいかもしれませんね。




「Stretching Stiffness」、「Bending Stiffness」を共に0にすると、ちょっと使えそうにありません。




「Damping」を1にすると布がフワフワしたようになびきます。しかし、これもローポリではムリがあるのかもしれません。メッシュが貫通しやすくなります。




「Damping」を0にすると塩ビ素材のようにベランベランとした感じになりますね。やはり、ローポリならば0.5ぐらいが無難でしょうか。

あと、「Solver Frequency(一秒間ごとのソルバー反復の回数)」は480あたりがちょうどいい気がします。

今回はこのような感じになりましたが、他のモーションをさせる時に設定の変更もありうるかもしれません。揺れモノは奥が深いですね。また長くなってしまいましたね、本日はこの辺で。(^^;)


テーマ: CG ジャンル: 日記
Visual Studio 2017のインストール
Unity



今朝、MicroSoft社からVisual Studio 2017の正式版が使えるようになったとお知らせメールが着ていました。VS2017はUnityとの連帯もさらに良くなっているそうです。

なので、早速インストルさせてもらうことにしました。とりあえず、Visual Studio Community 2015をアンインストールして30GBぐらいCドライブの空き領域を確保しておきました。




Visual Studio 2017のダウンロードのページから無償版の「Community 2017」をインストールしてみることにします。




何も選択していないVisual Studio 2017の本体のサイズは606MBとずいぶん小さいですね。ここから利用者の必要なものを選んで入れればいいのですね。




試しに全部選択してみると50.52GBとすごいことになります。全部入れておいてもいい気もしますが、さすがにこのサイズともなると躊躇しますね。まず、必要なものだけ入れておいて後から必要になったら追加するようにしておいた方がいいかもしれませんね。






とりあえず、今のところ自分的にはWindowsディスクトップアプリ関連とUnity関連だけで良さそうです。インストールサイズは17.5GBでお手頃です。(^^;)




インストールに時間がかかるものだと思っていましたが、昼食をとるタイミングでインストールを開始して30分ぐらいして戻ってきたら、もうインストールが済んでました。思っていた以上に早かったですね。Visual Studio 2015の時は3~4時間ぐらいかかったような気がします。(Update 3のときは何故か丸2日ぐらいかかりました・・・)




それで早速、Unityのスクリプトエディターに登録してみました。

Unityのメニューバーの[Edit >> Preferences]から[Unity Preferences]
パネルを開き、[External Tools >> External Script Editor]から、
[C:\ProgramData\Microsoft\Windows\Start Menu\Programs]
にある、「Visual Studio 2017」のショートカットを選びます。




これで、UnityでVisual Studio 2017をスクリプトエディターとして設定することが出来ました。UnityのスクリプトをダブルクリックするとVS2017がスクリプトエディターとして起ち上がりました。




onと二文字打っただけで入力候補がいっぱい出てきます。




現れた候補からOnCollisionEnterを確定すると、
private void OnCollisionEnter(Collision collision) {}
とprivate voidからパラメーターとしてcollisionまで用意してくれます。たった二文字からここまでしていただけるとは至れり尽くせりですね。(^^;)

VS2015まではOnCollisionやOnTriggerなど入力候補として現れてくれず、全文字をキー入力しないとなりませんでした。これはすごく便利になりましたね。

あと、クラス単位やメソッドごとに点線でくくられているので終わりのカッコがどこのカッコか判別しやすくなっていますね。

じつはUnity5.5はまだインストールしてないのですが、そろそろ入れてみたいですね。


テーマ: CG ジャンル: 日記
ユニティちゃんでゲーム制作演習
Unity



今から一年半ぐらい前にUnityの勉強を始めようと思っていた時、本屋で見つけとりあえずやってみようと初めて買ったUnity本が日経BP社の「ユニティちゃんでゲームを作ろう」というムックでした。

本に書かれている「UnityChanDash」を見よう見まねで実践したら何とかうまくいって動いてくれて、Unityを使えば思っていたより簡単にゲームらしいものが作れるんだなと感心した半面、プログラミングなど無縁だった自分にとってまるで意味が分からないコードや記号が一杯で、こんなのどうやって使いこなせるようになるのだろうかと絶望感にも似た感情を抱いたのも今でも覚えています。(^^;)

それでもUnityを触り始めて一年以上経って、今ではC#もそれなりに理解できるようになりました。そこで、ここまで自分が学習してきたUnityの知識のまとめとして、「UnityChanDash」にいろいろ機能を追加して一連のゲームアプリとしての形式が成り立つようにアレンジしてみたいと思いました。

まず、追加したいことの確認、

・タイトル画面を設けて、スタートボタンを押すとゲームスタート
・プレーヤーが走り出す前にカメラが前方から後方に回り込む
・カメラが定位置に着てから走り出す
・障害物に当たった時、ゴールした時、カメラがプレーヤーの正面に回り、UI表示する
・障害物に3回ぶつかるとゲームオーバー。その都度UIでスペア数を表示する
・ゲームオーバー、ゴール後にリトライ、タイトル画面にもどる、ゲーム終了の選択メニューを出す
・BGMと効果音を付ける
・Escキーで強制終了、メニューから終了でユニティちゃんライセンスを表示して終了する

というような感じです。

それで完成したので公開したいと思います。



「UnityChanDash~arranged~」
Windows版
(19MB)
MacOS版
(22MB)
WebGL版

- WebGL版URL -
http://initmusic.web.fc2.com/games/UnityChanDash_arranged_WebGL/index.html



スタンドアロン版とWebGL版をビルドしてみました。もしよかったら、試してみてください。Win版とmac版はオンラインストレージからzipをダウンロードして解凍して実行してください。制作とビルドはUnity5.4.1でしています。

WebGL版はWeb上のリンクとなっています。WebGL版はFireFoxでしか動作しないようです。ご使用しているブラウザが違う場合はFireFoxを立ち上げてから下のURLをコピペでお願いします。WebGL版では終了したいときはウィンドウを閉じてください。なお、「Unity WebGL」はスマホ等のモバイル端末には対応しておりません。

いちおうお断りしておきますが、ゲーム自体が面白いかどうかではなく、ゲームアプリとして一連の形式を取らせるということが目的ということなのでその辺りはご了承ください。(わざとミスなどして処理を確認していただけたらと思います)







「↑」キーかマウスの「左クリック」でジャンプ、「↓」キーか「右クリック」でスライディングで障害物を避けます。障害物に3回ぶつかるとゲームオーバーです。ゲーム中にPキーを押すたびにBGMのオンオフを切り替えられます。

WebGL版では影の描写をしないようにしています。余興でユニティちゃんライセンス表示中にBキーを押すとユニティちゃんの「バイバイ」ボイスがなります。

せっかくなので、自分の備忘録としてこのゲームで使った自分が追加した部分のスクリプトの解説を書いておきたいと思います。全部は長くなりすぎるので部分的ということで。

・走り出す処理

public class PlayerAnimationController : MonoBehaviour {

    bool RunStartCheck = false;

    void Update() {
        if (RunStartCheck) {
        GetComponent<Rigidbody>().MovePosition(transform.position + 
       transform.forward * Time.deltaTime * 3);
        }
    }

    public void RunStart() {
        RunStartCheck = true;
    }
以下略

まず、走り出すところですが、初めはインクリメント計算処理で一定時間待機にしてみましたが、そうすると初回とリロード後では微妙にタイミングが変わってしまいました。また、この方法では自分のPCでうまく合わせられても違うPCではタイミングが変わってしまう可能性もあります。ここは厳密に同じタイミングでスタートさせたいところです。

それで、bool型のRunStartCheck変数を用意してfalseにしておいてAnimationの方からユニティちゃんが待機状態からRun状態に移るタイミングで仕込んでいるイベントでRunStart()を実行してRunStartCheckをtrueにすることで前に動き出すようにしました。これだとタイミングはバッチリですね。




・スペア数で分岐等の処理


using UnityEngine;
using UnityEngine.UI;//UnityUIを使うための名前空間
using UnityEngine.SceneManagement;//SceneManagerを使うための名前空間
using System.Collections;

public class GameManagement : MonoBehaviour {

    public GameObject Branch;
    public Text mistakeText;
    public Text gameoverText;
    public Text spareText;
    public static int spare = 2;

    void Start() {
        spareText.text = spare.ToString(); //スペア数の表示、更新
    }

    //障害物にぶつかったらSendMessageを受信、スペアの数で処理の分岐
    void spareNum() {
        if(spare >= 1) {
            Invoke("mistake", 0.5f);
        }
        else if (spare == 0) {
            Invoke("gameover", 0.5f);
        }
    }
    //ミスしたとき、テキスト「MISTAKE」を表示させる処理
    void mistake() {
        mistakeText.gameObject.SetActive(true);
        Invoke("OnLoad", 6);
    }
    //ゲームオーバー時、テキスト「GAME OVER」を表示させる処理
    void gameover() {
        gameoverText.gameObject.SetActive(true);
        Invoke("TimeLag", 4);
    }
    //呼び出されたら、4秒後にReGameBranch()を実行
    void TimeLag() {
        Invoke("ReGameBranch", 4);
    }
    //ゲーム後に3つの選択肢を表示させる
    void ReGameBranch() {
        Branch.gameObject.SetActive(true);
    }
    //ミスしたらスペアを一人減らす、シーンを読み直す
    void OnLoad() {
        spare -= 1;
        SceneManager.LoadScene("UnityChanDash2016");
    }
    //選択肢1が押されたら、スペアを2に戻す、ゲームを始めからやり直す
    public void PushTryAgain() {
        spare = 2;
        SceneManager.LoadScene("UnityChanDash2016");
    }
    //選択肢2が押されたら、スペアを2に戻す、BGMを廃棄、タイトルに戻る
    public void PushReTitle() {
        spare = 2;
        bgmloop.DestroyOn();
        SceneManager.LoadScene("UCD_Title");
    }
    //選択肢3が押されたら、ゲームを終了、ライセンス表示シーンに移行
    public void GameQuit() {
        SceneManager.LoadScene("LicenseLogo");
    }
}

スペアの数のspare変数はシーンを読み直しても維持されるようにpublic staticで宣言しておきます。時間差が欲しいとき便利なInvoke()メソッドを多用しましたが、今思えばAnimationのイベントを使えばもう少しスッキリ出来たかもしれません。もう直す気はありませんが。(^^;)

・BGMをシーンをまたいでループで流す

単にBGMを付けたいとき、一曲であればAudioSourceコンポーネントを追加してAudioClipに指定して「Play On Awake」をオンにしておけばノンコーディングでシーン開始時から流すことが出来ます。しかし、この場合はシーンを読み直すと始めから再生されます。



今回の場合、ゲームプレイ中はリプレイしても途切れないでずっとループさせた方が良いと考えました。そうすると、シーンをまたいで再生し続ける必要があります。色々試してみてうまくいった方法を書いておきたいと思います。

まず、空のゲームオブジェクト(名前はMusicBox)にBGM用のAudioSourceコンポーネントを追加して、DontDestroyOnLoadを使ってシーンをまたいでもこのゲームオブジェクトが破棄されないようにしてみました。でも、これだけだとシーンが呼び出されるたびにBGMが重なっていってしまいます。

それで、このMusicBoxをインスタンス化してprefabとしてスクリプトからResources.Loadを使って呼び出せるようにして、BGMを初回のみ再生させ次回以降は再生させないようにして、タイトルに戻るときはDestroy()でゲームオブジェクトを破棄するという方法を取ることでうまくいくことができました。

public class GameManagement : MonoBehaviour {

    private GameObject BGMobj;
    private BGM_Loop bgmloop;
    public static bool musicOn = true;

    void Start() {
        Instantiate(Resources.Load("Prefabs/MusicBox"), new Vector3(0, 0, 0),
        Quaternion.identity);

        BGMobj = GameObject.Find("MusicBox(Clone)");
        bgmloop = BGMobj.GetComponent<BGM_Loop>();
    }
以下略

GameManagementクラスのBGM関連の部分です。Start()で "Resources/Prefabs/"フォルダに入れておいたMusicBoxを取り出します。そして、GameObject.Find()でBGMobj変数に格納します。ちなみに、このとき呼び出したMusicBoxには(Clone)が付いているのでそれを含めて名前にしておかないと見つけてくれません。

これは、MusicBoxにアタッチしているBGM_Loopスクリプトです。

public class BGM_Loop : MonoBehaviour {

    public AudioSource audioSource;
    public static bool shokaiCheck = true;

    void Start() {

        if (shokaiCheck) {
        shokaiCheck = false;
        DontDestroyOnLoad(gameObject);

        audioSource = GetComponent<AudioSource>();
        audioSource.Play();
        }
    }

    public void DestroyOn() {
        shokaiCheck = true;
        Destroy(gameObject);
    }
    public void BGM_Play() {
        audioSource.Play();
    }
    public void BGM_Stop() {
        audioSource.Stop();
    }
}

bool型で初回チェック用のshokaiCheck変数をpublic staticで宣言しておきます。こうすることによってその状態はシーンをまたいでも保たれます。「Play On Awake」はオフにしておきます。

shokaiCheckは始めはtrueなのでif文の中に入ります。そこでshokaiCheckをfalseに変えておき、"MusicBox(clone)"をDontDestroyOnLoadにします。そして、ここでBGMを再生させます。

これでシーンが呼び直されても次回からはshokaiCheckはfalseなのでBGMは重ねて再生されることはなくなります。タイトルに戻るときはDestroyOn()でオブジェクトを破棄するとBGMは止まります。破棄する前にshokaiCheckはtrueに戻しておきます。こうしておくことで、タイトルに戻って再びスタートボタンを押したときにBGMがまた始めに再生される処理に入ります。BGM_Play()、BGM_Stop()はPキーを押した時用です。

ユニティちゃんの掛け声ですが、同時に再生することはないので一つのAudioSourceに各音声をAudioClip型の配列にそれぞれ格納しておいて、各Animationのイベントからその都度入れ替えて再生させています。



public class PlayerAnimationController : MonoBehaviour {

    public AudioClip[] voice;
    private AudioSource audiosource;

    void Start() {
        audiosource = GetComponent<AudioSource>();
    }

    void slideVoice() {
        audiosource.clip = voice[0];
        audiosource.Play();
    }
    void jumpVoice() {
        audiosource.clip = voice[1];
        audiosource.Play();
    }
    void damageVoice() {
        audiosource.clip = voice[2];
        audiosource.Play();
    }
    void loseVoice() {
        audiosource.clip = voice[3];
        audiosource.Play();
    }
    void goalVoice() {
        audiosource.clip = voice[4];
        audiosource.Play();
    }
    void ufufuVoice() {
        audiosource.clip = voice[5];
        audiosource.Play();
    }

ちなみに、BGMからユニティちゃんボイスもすべてwav形式だったのでmp3に変換して7MBほど軽量化したのですが、ビルドした総サイズを比べると1MBぐらいしか差がありませんでした。それでも、mp3の方が少しは軽くなりますね。

これは最後のライセンス表示シーンで使っているスクリプトです。

using UnityEngine;
using System.Collections;

public class LicenseLogo : MonoBehaviour {

    public AudioSource audioSource;
    private GameObject BGMobj;
    private BGM_Loop bgmloop;
    public static bool musicOn2;

    void Start() {
        musicOn2 = GameManagement.musicOn;
        BGMobj = GameObject.Find("MusicBox(Clone)");
        bgmloop = BGMobj.GetComponent<BGM_Loop>();
        audioSource = GetComponent<AudioSource>();
        audioSource.Play(); //ユニティちゃん「バイバイ」音声の再生
    }

    void Update() {
    //Pキーが押されるたびにBGMの再生と停止を交互させる
        if (Input.GetKeyDown(KeyCode.P)) {
           if (musicOn2) {
               bgmloop.audioSource.Stop();
               musicOn2 = false;
               return;
            }
            if (!musicOn2) {
               bgmloop.audioSource.Play();
               musicOn2 = true;
               return;
            }
        }
    //Bキーが押されたらユニティちゃん「バイバイ」音声の再生
        if (Input.GetKeyDown(KeyCode.B)) {
            audioSource.Play();
        }
    }
    //アプリケーションを閉じる
    void QuitLogo() {
        Application.Quit();
    }
}

ゲーム中のBGMをオンオフ出来るようにしてしまったため、このアプリを終了するだけのシーンのためにスクリプトをこれだけ書く事になってしまいました。本来ならば最後のQuitLogo()だけあればいいところなのですが(^^;)。ちなみに、ロゴがフェイドアウトしていくタイミングでAnimationのイベントからQuitLogo()を実行するようにしています(WebGLでは機能はしません)。

musicOnはGameManagementクラスでpublic staticのbool型で宣言してある変数でBGMの再生状態を格納してあります。それをこのクラスでも引き継がせないと都合が悪いことが分かったのでmusicOn2に代入しておきました。public staticの変数はシーンをまたいで他のクラスに値を渡せるのですね。

という感じで、部分的な解説なのですが、これでもものすごく長くなってしまいましたね(^^;)。しかし、解るようになるとプログラミングは面白いですね。もし、Unityを始めてなかったら自分がプログラミングなど理解できるようになることはなかったと思います。プログラミングの面白さを知ることが出来たのもUnityのおかげです。

来年こそはオリジナルキャラを使ってなにか作品をつくれたらいいなぁと考えています。しかし、そのためにはやることがいっぱいで時間がいくらあっても足りないぐらいですが、めげずに来年こそは!(笑)





テーマ: CG ジャンル: 日記
Unityでのトゥーンセットアップ
Unity



今回はUnity用のオリキャラ「カレン」をUnityのトゥーンシェーダーを使ってセットアップしてみたいと思います。




今回使用するこのキャラのFBXはShade 3Dから直接エクスポートしたものです。




まず、メニューバーの[Assets >> Import Package >> Effects]にある「ToonShading」をインポートしておきます。これでシェーダーに「Toon」が追加されます。




トゥーン調にしたいマテリアルに「ToonBasicOutline」を割り当てます。目の影は半透明で表現していますが「ToonBasicOutline」では透明度が反映されないので「Standard」のままです。このトゥーンシェーダーだと法線マップも反映されないのでテクスチャーは描き直しました。




Unityでは共通なプロパティーであれば複数選択しておくことで一括で変更できるので便利ですね。




う~ん、何か残念な感じです。このままではちょっと使えませんね。少しスクリプトを弄る必要があるようです。近づけば輪郭線の太さも良さ気に思える時もありますが、離れると線が太くなっていくように見えてしまいます。キャラクターに近づけば太くなり、遠ざかれば細くなるようにしたいです。

そこで、まず「ToonBasicOutline.shader」をエディタで開いてみると、38行目にある
o.pos.xy += offset * o.pos.z * _Outline;
のo.pos.zがカメラからの距離によらず輪郭線の太さを一定にしているところなので、それを消して
o.pos.xy += offset * _Outline;
と書き換えます。

これで、カメラからの距離(Z値)によって輪郭線の太さが変わるようになります。




輪郭線の色と太さはインスペクター上でマテリアルごとに変更ができます。しかし、輪郭線の太さを一番細くしてもまだ太く見えます。これは、スクリプトで最小値が0.002より小さく出来ないように制限されているからのようです。

5行目にある、
_Outline ("Outline width", Range (.002, 0.03)) = .005
という部分がその制限範囲のようです。ですので、Range (.002, 0.03)はRange (0.0, 0.03)と書き直して最小値を0にしてみます。




これで輪郭線の太さをちょうどいい具合の0.0015まで値を小さく出来ました。しかし、輪郭線がギザギザしていて綺麗に見えないのが気になります。

これはアンチエイリアスをもっと強めにかければ解決しそうです。メニューバーから[Edit >> Project Settings >> Quality]と辿って行くと「Anti Aliasing」の設定項目があります。



ここを「4x Multi Sampling」以上にすると綺麗な感じになります。







これは、「Anti Aliasing」を「8x Multi Sampling」にした図です。これで、自然なトゥーン調になりました。あと、白目と口内の輪郭線は無い方が良いので太さを0にしてあります。

MMD用モデルを編集するときに使うPMXEでは輪郭線の設定等はサーフェスグループごとに細かく設定できるのですが、Unityの場合はマスターサーフェスごととなるようです。

白目と口内は当初は顔のパーツのマスターサーフェス(同一テクスチャー)に入れていたので、そのままでは輪郭線を消せませんでした。なので白目と口内は独立したマテリアルにして個々に輪郭線の設定が出来るようにしました。(ちなみに、目の影部もそういう理由で独立してあります)

Unityの標準シェーダーのカリング設定では片面ポリゴンの場合裏面が表示されません、両面表示にしたいときはスクリプトを書き直す必要があります。このキャラの腰巻きなどは片面ポリゴンなのでその作業をする必要があるのかと思ったら、トゥーンシェーダーでは両面表示が標準のようですね。

このキャラクターのボーンとスキンの設定はすでに終えていて、記念にUnity上でアニメーションでもと思っていたのですが、さらに長くなりそうなので、ここで区切りとして次回に持ち越したいと思います。


テーマ: CG ジャンル: 日記
Unity5.4 正式リリース
Unity



先月の7月28日、Unity5.4が正式リリースされました。

以前は、超クオリティーなリアルさを求めるならUnreal Engine、アニメっぽい、デフォルメ的ならUnityとか思っていましたが、現在のUnityはUEぐらいな高クオリティーのリアルな感じも十分表現出来る感じになってますね。今後もっと進化するのでしょうか。楽しみです。

早速、Unity5.4をインストールしてみました。

セキュリティーの脆弱性があるということで近い内に廃止されるとの噂があった「Unity Web Player」が5.4で本当にインストーラーから姿を消したようです。






今後も、「Web Player」を使いたい場合はUnity5.3以前のバージョンでビルドして欲しいとのこと。今後は、「Web Player」の代わりに「WebGL」を使うということになるのでしょう。「WebGL」はまだ試したことはありませんが、「Web Player」と同じような感じなんでしょうかね。

Unityを初めてインストールしてみたのがちょうど一年前ぐらいでした。始めはプログラミングなどもまったく分からず不慣れな作業で手こずりましたが触っている内に少しづつ理解できるようになりました。

しかしながら、3Dモデリングをし始めるとUnityをまったくいじれなくなるし、Unityを勉強しはじめるとモデリングを全くしなくなるのですよね(数ヶ月単位で)。どちらも一度始めるとそれなりの時間が必要になってしまうんです。

Unityに関しては今まで特に書くことも無かったのですが、日々出来ることも増えつつあるので初心者の目線で書いてみたいことも出てきました。今後はUnityのトピックも増やせていけたらと思います。


テーマ: CG ジャンル: 日記
カテゴリ
ini-T MUSIC SKY
プロフィール