バーチャルユーチューバーへの第一歩、Unity3D上でOculusTouchのトラッキングをモデルに連動させる

<img src="http://megamin.jp/wp-content/uploads/2018/02/medama_20180216_0141.png" />

# 概要

- プロジェクトを作成し、モデルとモーションの準備
- Unity 上で VR デバイスを使用できるようにする
- Humanoid リグの設定されたモデルを Oculus Touch の動きに連動させる
- 画面内に自分を映したモニタ映像を表示させる

# やる気出ない

　度々やる気が出たり出なかったりの波が激しくなることがあり、今猛烈にやる気出ないです。やる気が出ないので無理やり手を動かしてみます。とりあえず手を動かすと案外体は動くものですね。よしがんばって Oculus でキャラクターを動かしてみるぞ。

# プロジェクトを作成し、モデルとモーションの準備

<img alt='' class='alignnone size-full wp-image-2229 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860b51b7573.png' />

- Unity3D を起動します

<img alt='' class='alignnone size-full wp-image-2230 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860b6051704.png' />

- New

<img alt='' class='alignnone size-full wp-image-2231 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860b6d2aa28.png' />

- プロジェクト名を適宜入力し、Create project

　今回も新規プロジェクト作成から進めていきます。新規プロジェクトを作成したらとりあえず必要な素材として Humanoid モデルとアイドリングモーションをインポートします。 モデルは以前作成しためがみん素体を使用します。アイドリングモーションはアセットストアから MORRO MOTION の Idle MoCap を使用する事にします。

- <a href="http://megamin.jp/wp-content/uploads/2018/02/megamin_20180216_0226.zip">めがみん素体モデル</a>をダウンロードし、解凍する

<img alt='' class='alignnone size-full wp-image-2232 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860b8340f98.png' />

- Project ビューの何もないところを右クリックして Create → Folder
- フォルダ名を Models に設定する

<img alt='' class='alignnone size-full wp-image-2233 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860b9017ab8.png' />

- 先ほどダウンロード・解凍した FBX ファイルを Project ビューの Models フォルダへドロップする

<img alt='' class='alignnone size-full wp-image-2234 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860b9cbaac9.png' />

- Project ビューの Models フォルダを展開し、インポートした FBX をクリック
- Inspector ビューの Rig をクリック
- Animation Type プロパティを Humanoid に設定し、 Apply

<img alt='' class='alignnone size-full wp-image-2235 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860bad80986.png' />

- Window → Asset Store

<img alt='' class='alignnone size-full wp-image-2236 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860bb8dd865.png' />

- Asset Store ビュー検索窓で Idle MoCap を入力して Enter

<img alt='' class='alignnone size-full wp-image-2237 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860bc3d7da8.png' />

- Asset Store ビュー検索結果ページを下にスクロールさせ、Idle MoCap をクリック

<img alt='' class='alignnone size-full wp-image-2238 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860bd055e58.png' />

- Asset Store アセット詳細ページを下にスクロールさせ、ダウンロードをクリック

<img alt='' class='alignnone size-full wp-image-2239 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860bdcc0860.png' />

- Import

<img alt='' class='alignnone size-full wp-image-2240 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860be9d6957.png' />

- Project ビューの Models フォルダを右クリックし、Create → Animator Controller
- コントローラ名を MegaminController に設定

<img alt='' class='alignnone size-full wp-image-2241 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860bf9af6c4.png' />

- Project ビューの MegaminController をダブルクリックし、Animator ビューを開く

<img alt='' class='alignnone size-full wp-image-2242 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c0c65048.png' />

- Animator ビューの Base Layer の歯車マークをクリック
- IK Pass をチェック

<img alt='' class='alignnone size-full wp-image-2243 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c1eefbeb.png' />

- Project ビューの Idle MoCap フォルダを展開し、Idle stance 2 モーションを Animator ビューにドロップし、ステートを追加する
- 自動的に Entry ノードからリンクが作成される（リンクというか、transition?）

<img alt='' class='alignnone size-full wp-image-2244 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c2e7ff8d.png' />

- Hierarchy ビューのモデルオブジェクトをクリック
- Project ビューの MegaminController を Inspector ビューの Controller プロパティへ設定する

<img alt='' class='alignnone size-full wp-image-2245 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c3d088c6.png' />

- 実行してみてモーションが適用されていれば OK

次に色々制御するのに都合を良くするために、モデルオブジェクトに親階層を作成することにします。

<img alt='' class='alignnone size-full wp-image-2246 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c488068c.png' />

- Hierarchy ビューの何もないところを右クリックし、Create Empty
- 作成された GameObject をクリックし、Inspector ビューで名前を MegaminRoot に設定
- Transform の値が Position 及び Rotation の値が全て 0、Scale の値が全て 1 になっている事を確認する（なっていなければそれぞれ 0、1 に設定）

<img alt='' class='alignnone size-full wp-image-2247 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c5b8ab1f.png' />

- Hierarchy ビューのモデルオブジェクトを MegaminRoot にドロップし、MegaminRoot の子ノードに設定

次に、Oculus Rift ヘッドセットと Touch コントローラをトラッキングするオブジェクトを追加します。

<img alt='' class='alignnone size-full wp-image-2248 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c6dd1791.png' />

- Hierarchy ビューの MegaminRoot を右クリックし、Create Empty を3 回実行し、空のゲームオブジェクトを 3 つ作成する
- 作成した GameObject をリネームし、それぞれ Head、RightHand、LeftHand に設定

# Unity 上で VR デバイスを使用できるようにする

　モデルの準備ができたので、次は VR デバイスを使用できるようにします。うちは HTC Vive と Oculus Rift + touch を持ってますが、今回は Oculus を使用する前提で進めていきます。

<img alt='' class='alignnone size-full wp-image-2249 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c7bd4520.png' />

- Edit → Project Settings → Player

<img alt='' class='alignnone size-full wp-image-2250 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c8bbfde4.png' />

- Inspector ビューの XR Settings を開き、Virtual Reality Supported をチェックする

これだけで、プログラムの実行で Oculus に実行結果が表示されるようになります。
次は、制御用のスクリプトを作成します。

<img alt='' class='alignnone size-full wp-image-2251 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860c97a44b5.png' />

- Project ビューの何も無いところを右クリックし、Create → Folder
- 新規フォルダ名を Scripts に設定

<img alt='' class='alignnone size-full wp-image-2252 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860ca62e4fc.png' />

- Project ビューの Scripts を右クリックし、Create → C# Script
- 作成したスクリプト名を IKController に設定し、ソースコードを下記の通り編集する

```cs:IKController.cs
using UnityEngine;
using UnityEngine.XR;

[RequireComponent(typeof(Animator))]
public class IKController : MonoBehaviour {

    protected Animator animator;
    public bool ikActive = false;
    public Transform rightHandObj = null;
    public Transform leftHandObj = null;
    public Transform headObj = null;

    void Start() {
        animator = GetComponent<Animator>();
        XRDevice.SetTrackingSpaceType(TrackingSpaceType.Stationary);
    }

    void Update() {
        // Rキーで位置トラッキングをリセットする（Stationaryでしか動作しない）
        if (Input.GetKeyDown(KeyCode.R)) {
            InputTracking.Recenter();
        }
    }

    void OnAnimatorIK() {
        if (animator) {

            //if the IK is active, set the position and rotation directly to the goal. 
            if (ikActive) {
                // Set the look target position, if one has been assigned
                if (headObj != null) {
                    animator.SetLookAtWeight(1);
                    animator.SetLookAtPosition(headObj.position);
                }

                // Set the right hand target position and rotation, if one has been assigned
                if (rightHandObj != null) {
                    animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
                    animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1);
                    animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);
                    animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);
                }

                // Set the left hand target position and rotation, if one has been assigned
                if (leftHandObj != null) {
                    animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, 1);
                    animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, 1);
                    animator.SetIKPosition(AvatarIKGoal.LeftHand, leftHandObj.position);
                    animator.SetIKRotation(AvatarIKGoal.LeftHand, leftHandObj.rotation);
                }

            }

            //if the IK is not active, set the position and rotation of the hand and head back to the original position
            else {
                animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0);
                animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0);
                animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, 0);
                animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, 0);
                animator.SetLookAtWeight(0);
            }
        }
    }
}
```

<img alt='' class='alignnone size-full wp-image-2253 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860cbfb7ba9.png' />

- Project ビューの IKController を Hierarchy ビューのモデルにドロップし、コンポーネントをオブジェクトに紐づける

# Humanoid リグの設定されたモデルを Oculus Touch の動きに連動させる

　モデルの動きを Oculus のトラッキングに連動させるために、Oculus SDK を使用します。

- <a href="https://developer.oculus.com/downloads/" target="_blank">Oculus SDK のダウンロードページ</a>へアクセス

<img alt='' class='alignnone size-full wp-image-2254 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860ccf3c439.png' />

- Unity をクリック

<img alt='' class='alignnone size-full wp-image-2255 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860cddd727e.png' />

- Oculus Utilities for Unity をクリック

<img alt='' class='alignnone size-full wp-image-2256 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860cea8490f.png' />

- I have read and agree to the terms of the EULA, Terms of Use and Privacy Policy を確認し、チェックする
- Download をクリック

<img alt='' class='alignnone size-full wp-image-2257 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860cfacffad.png' />

- ダウンロードしたファイルを展開する

<img alt='' class='alignnone size-full wp-image-2258 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d0a43634.png' />

- 展開した圧縮ファイル内の OculusUtilities.unitypackage をダブルクリックする

<img alt='' class='alignnone size-full wp-image-2259 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d14414ce.png' />

- Import

<img alt='' class='alignnone size-full wp-image-2260 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d1e8f583.png' />

- 何気に新しいバージョンのプラグインが出てるそうなのでここは Yes

<img alt='' class='alignnone size-full wp-image-2261 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d2871f4b.png' />

- エディターの再起動を提案されたので、ここは素直に従って Restart

<img alt='' class='alignnone size-full wp-image-2262 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d32b1b5a.png' />

- シーンのセーブをするか問われたのでここは当然 Save

<img alt='' class='alignnone size-full wp-image-2263 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d3e92a4c.png' />

- 新しいフォルダー

<img alt='' class='alignnone size-full wp-image-2264 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d4853a4f.png' />

- フォルダ名を Scenes に設定し、ダブルクリックしてフォルダ内へ移動

<img alt='' class='alignnone size-full wp-image-2265 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d58e4ee2.png' />

- VTuberTest という名前で保存する

この後、UnityEditor が再起動します。

<img alt='' class='alignnone size-full wp-image-2266 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d6825426.png' />

- Project ビューの OVR / Prefabs フォルダを展開し、OVRCameraRig を Hierarchy ビューの MegaminRoot にドロップする

<img alt='' class='alignnone size-full wp-image-2267 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d7159e4a.png' />

- めがみんモデルのサイズがちょっとバカでかかったので、身長 155cm くらいにするためにスケール値を 0.335 くらいに設定する

<img alt='' class='alignnone size-full wp-image-2268 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d7c3eddf.png' />

- Hierarchy ビューの Head を CenterEyeAnchor にドロップする

<img alt='' class='alignnone size-full wp-image-2269 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d8816384.png' />

- Head オブジェクトをモデルの注目点として使用するため、CenterEyeAnchor よりちょっと前方に移動させておく
- Hierarchy ビューの Head をクリックしInspector ビューの Transform を Position = （0, 0, 10）、Rotation = （0, 0, 0）、Scale = （1, 1, 1）に設定

<img alt='' class='alignnone size-full wp-image-2270 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860d9e16c73.png' />

- Hierarchy ビューの OVRCameraRig をクリック
- Inspector ビューの Transform を Position = （0, 1.5, 0）に設定
- Trancking Origin Type を EyeLevel に設定

<img alt='' class='alignnone size-full wp-image-2271 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860da84aa41.png' />

- Hierarchy ビューのモデルオブジェクトをクリック
- Inspector ビューの IK Active をチェック
- Hierarchy ビューの Head を Inspector ビューの Head Obj にドロップ
- Hierarchy ビューの RightHandAnchor を Inspector ビューの Right Hand Obj にドロップ
- Hierarchy ビューの LeftHandAnchor を Inspector ビューの Left Hand Obj にドロップ

以上で最低限の挙動が設定できたはずっ

<img alt='' class='alignnone size-full wp-image-2272 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860db1cea88.png' />

- 実行してみる

<img alt='' class='alignnone size-full wp-image-2273 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860dbb08f37.png' />

おぉ、動いた！！

ただ、まだまだ問題点があるのでこれからはちょっと色々微調整が必要そうです。

- 座った姿勢の状態で収録できるように、EyeLevel に設定したものの、初期位置がどうも床に合わせられてるような気がする
- 初期位置が OVRCameraRig を設定した位置よりも前に移動してるような気がする
- でもまぁ立って自分が位置を微調整すれば済む事なので（いやそれよくないだろ）

でもまぁ、動いたのでよしとします。次は、バーチャル空間内で自分の姿が見れるように設定します。

# 画面内に自分を映したモニタ映像を表示させる

　で、とりあえず Oculus でモデルを制御するところまでは出来ましたが、自分がどんな風に映っているのかがわからないので、シーン内に自分の姿を表示させるようにします。具体的にはこんなイメージです。

<img alt='' class='alignnone size-full wp-image-2274 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860dcd56a1d.png' />

具体的には、シーン内にカメラを設置し、レンダーテクスチャにレンダリングし、シーン内にレンダーれくすちゃを張り付けたオブジェクトを配置します。ではやってみましょう。

<img alt='' class='alignnone size-full wp-image-2275 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860dd707d51.png' />

- Project ビューの何もないところを右クリックし、Create → Render Texture
- 作成した RenderTexture の名前を VRCamera に設定

<img alt='' class='alignnone size-full wp-image-2276 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860de3014ee.png' />

- プロジェクト作成時に元から存在していたカメラを流用します
- Hierarchy ビューの Main Camera を選択し、Inspector ビューの Audio Listener の歯車マークをクリックし、Remove Component をクリックして、Audio Listener を削除
    - Audio Listener OVRCameraRig 以下のカメラオブジェクトにも存在しているため、重複したものを削除する必要があるというのが理由

<img alt='' class='alignnone size-full wp-image-2277 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860df44fa3f.png' />

- Hierarchy ビューの Main Camera をクリック
- Project ビューの VR Camera を Inspector ビューの Target Texture にドロップ

<img alt='' class='alignnone size-full wp-image-2278 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860dffbc5a2.png' />

- Hierarchy viewの Main Camera を CenterEyeAnchor にドロップ

<img alt='' class='alignnone size-full wp-image-2279 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860e09b53de.png' />

- Hierarchy ビューの Main Camera をクリック
- Inspector ビューの Transform を Position = （0, -0.5, 3）、Rotation = (0, 180, 0）に設定
- これで、自分の視線の先にカメラがあり、常に自分を映している状態になる

<img alt='' class='alignnone size-full wp-image-2280 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860e1649c06.png' />

- Hierarchy ビューの CenterEyeAnchor を右クリックし、3D Object → Plane をクリック

<img alt='' class='alignnone size-full wp-image-2281 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860e254078c.png' />

- Hierarchy ビューの Plane をクリック
- Inspector ビューの Transform を Position = （0, 0, 10）、Rotation = （270, 0, 0）、Scale = （1, 1, -1）に設定
- Project ビューの VR Camera を Hierarchy ビューの Plane にドロップ

<img alt='' class='alignnone size-full wp-image-2282 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860e31afb0a.png' />

- 実行してみる

<img alt='' class='alignnone size-full wp-image-2283 ' src='http://megamin.jp/wp-content/uploads/2018/02/img_5a860e3cd3499.png' />

おおお、映ったわ。

# ここまでできたら後は簡単（多分）

　とりあえずこれで最低限な仕組みはできましたが、色々と気になる点はあります。

- Oculus SDK を使っているので、他の XR デバイスに対応させる時はまた考えないといけない
- 直接 Oculus のコンポーネントを突っ込むのではなく、いったん何かのオブジェクト経由でトラッキング情報を持ってきた方が良いと思う
- 動画収録用のウインドウを別途表示させたいので、あともうひとつカメラが必要かもかも
- 次はシーンの作り込みとかも必要ですね
- あれもやりたいこれもやりたい

と、色々夢が膨らんできたところで今日はここまで。

ではまた！