VR IKでVRコスプレをする時のハマり所とソリューション(Oculus Rift想定)

#はじめに
Oculus Rift Advent Calendar 2017 4日目の記事です！
Qiitaで記事を投稿するのは初めてな上、夏のセールでOculus Riftを初めて手に取った新参者ですがよろしくお願いします！

普段はこんな動画を投稿して遊んでいます。（いわゆる淫夢ネタが多分にあるのでご注意下さい。）
http://www.nicovideo.jp/watch/sm31592149

VRコスプレをするにあたって、参考にさせていただいたQiitaの記事がいくつもありますが最も直接参考になったのは以下の2記事です。
https://qiita.com/halne369/items/daadf0e00330a1019830
https://qiita.com/UnagiHuman/items/6168950edfbc28e48da6
はるねずみさん、UnagiHumanさんありがとうございます！

ただ、そのまま真似しようとした際いくつかハマり所がありました……
本記事では、Oculus RiftとFinal IKを使ってVRコスプレをする際の手順とハマり所を解説していき、誰でも簡単に好きなキャラクターになるためのお手伝いができれば幸いです！

#実際に使ったもの、アセット
1. Unity 2017.2.0f3
2. oculus Rift CV1+Touch
3. oculus Utilities 1.20
4. oculus Platform
5. oculus Avatar
6. 好きな（なりたい）3Dモデル
　<br>今回はこちらを使わせて頂いています。<br>https://www.assetstore.unity3d.com/jp/#!/content/15653
7. Final IK(https://www.assetstore.unity3d.com/jp/#!/content/14290)
8. Playmaker（これはプログラムが書ける人には不要だと思います……どうしても勉強より先に実践したかったので導入しています）

上記のアセット、SDK類が全てインストールされている前提で話を進めます。
 
#実際の作業手順・Hierarchy構成
##事前設定
では、早速作業に入る前に、一つだけ設定をします。
上部メニューのFile→Build settingを選択し、以下のような画面が出てきたら左下のPlayer Settings...をクリックして下さい。

![setting.PNG](https://qiita-image-store.s3.amazonaws.com/0/194196/e9035e41-b742-c4ac-7606-dad044c1782d.png)
するとInspectorに設定画面が現れるので、画面下部のXR settingsを選択、"Virtual Reality Supported"にチェックを入れます。
その下にVirtual Reality SDKsというリストが出てきますが、ここの一番上がOculusになっているようにします。
たまにヘッドセットに画面が映らないことがあるのですが、このリスト上からなぜかOculusが消えていたせいだったということが何度かありました。動作しない場合はぜひ確認してみて下さい。(ハマりポイントその1)
![801050381b09fc1ed8f8b1e1274afc55.png](https://qiita-image-store.s3.amazonaws.com/0/194196/a234b039-dcb8-3212-da51-6b4090e5a620.png)

##Hierarchy構成
それでは、本題に入ります。
先に、最小構成での完成したHierarchyを貼っておきます。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/194196/f3f5dc9b-c9ce-e140-adc3-85cd039c863b.png)

"CameraRoot"と"CharaRoot"という二つの空ゲームオブジェクトを作成し、その下にそれぞれ必要なものを配置していく形になります。
私のような初学者のために、コメントだけでなく流れをすべて説明していこうと思います。
##CameraRoot
まずCameraRootの下に空のゲームオブジェクト"HeightOffset"を配置します。
ここにキャラの地面から目までの高さ(メートル単位。今回の場合YのPositionに1.48)を入力し、Oculusのカメラを"HeightOffset"の下に配置することでキャラクターそのものの身長から世界を見ることができます。

早速、Project/Asset/OVR/Prefabsから"OVRCameraRig"というプレハブを先程の"HeightOffset"の下に配置します。
このOVRCameraRigの下にあるCenterEyeAnchorは、ヘッドセットの位置、傾きをリアルタイムで保持しているほか、ヘッドセット上での視界を担うカメラとしても機能しています。（なのでカメラの設定をいじる際はここをいじってください。）
せっかくなので今のうちにカメラの設定をいじっておきましょう。
"CenterEyeAnchor"にアタッチされているCameraコンポーネントの中のClipping PlanesのNearを0.01にします。
これはカメラから1cmよりも近くにあるものは非表示にする、という設定です。
初期値は0.3ですが、これだと30cmより近くにあるものを問答無用で非表示にするので、顔の近くに手を持ってきた際プレゼンスが失われます。
重大な副作用として、そのままではキャラの顔を内側から見ることになり、非常に気持ちが悪いことになります。
この回避方法は、他の設定が完了した後に説明します。

次に、"CenterEyeAnchor" "LeftHandAnchor" "RightHandAnchor"の3つの下に、
"CenterEyeTarget" "LeftHandTarget" "RightHandTarget"という空のゲームオブジェクトを設置します。
"Left/RightHandAnchor"はコントローラーの位置、傾きを反映しているので、ここの座標を直接用いて3Dモデルと同期させればいいと思うのですが、使う3Dモデルによってはそのままではうまくいかず、腕がねじれてしまうことがあります。<b>（ハマりポイントその2）</b>
現にこのモデルでは問題が発生しました。以下のツイートに参考動画があります。

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">Unity+Oculus RiftでのVRコスプレ進捗動画です。<br>もうなりふり構わないので誰か助けてください！！！！！<br>美少女になりたい！！！<a href="https://twitter.com/hashtag/VR?src=hash&amp;ref_src=twsrc%5Etfw">#VR</a> <a href="https://twitter.com/hashtag/VR%E3%82%B3%E3%82%B9%E3%83%97%E3%83%AC?src=hash&amp;ref_src=twsrc%5Etfw">#VRコスプレ</a> <a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://t.co/jRiVBu5ypE">pic.twitter.com/jRiVBu5ypE</a></p>&mdash; karinTSVR (@karin_tsvr) <a href="https://twitter.com/karin_tsvr/status/905391655351599104?ref_src=twsrc%5Etfw">2017年9月6日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


今回の場合、
LeftHandTargetのRotation値をX:-90 Z:90
RightHandTargetのRotation値をX:-90 Z:-90
にすることで手が自然な動きになりました。
<b>(ハマりポイントその3)</b>
##CharaRoot
「キャラクタールート」の略です。念のため。
こちらには実際にVRIKと同期させるゲームオブジェクトと、自分の体として用いる3Dキャラを格納します。

まず、CharaRootの下にTrackingSpaceDummyという空ゲームオブジェクトを配置し、さらにその下に"CenterEyeDummy" "Left/RightHandDummy"の合計3つの空ゲームオブジェクトを作成します。
これはまだただの空ゲームオブジェクトであり、何かを追跡しているわけではないので、それぞれに対応したCameraRootにある各Anchorと同期させる必要があります。
申し訳ないのですがPlaymakerで実装しているのでスクリプトの紹介はできません……
一応、アルゴリズム（というのもおこがましいですが）の紹介をしておくので、自力でスクリプトを書いていただくかPlaymakerを買ってください。

こちらがCameraRoot側、"centerEyeAnchorDummy"の実装です。
毎フレームXYZの座標、回転を取得し、変数に格納します。
"Left/RightHandTarget"にも同じ実装をして下さい。
![CEAD.PNG](https://qiita-image-store.s3.amazonaws.com/0/194196/b18dc3fe-f911-e7eb-dcef-68bc2275e72e.png)

CharaRootに戻って、"CenterEyeDummy"の実装です。
先程格納した変数を、毎フレームLate Update内で座標、回転に代入して下さい。
![CED.PNG](https://qiita-image-store.s3.amazonaws.com/0/194196/8b437424-aff9-340b-f8cb-323335e8fcc4.png)

これで下準備は完了です。最後に、3Dキャラクターの一番上の階層にVR IKをアタッチします。(今回の場合"F05_casualwear_00_h")
![VRIK.PNG](https://qiita-image-store.s3.amazonaws.com/0/194196/d3d1d926-6f21-8471-e78e-6f28f609d4f9.png)
画像のとおりに、各Targetに用意したDummyを貼り付ければ完成です。
他のパラメータはひとまず初期値で大丈夫ですが、"Position Weight"、"Rotation Weight"が1になっているのを確認して下さい。
"Weight"というのは、Targetの座標や回転に3Dモデルを追従させる力のこと（と理解している）なので、これが0になっているとキャラが動かず首をかしげることになります。
また、"Plant Feet"（常に床に接地するようにする？）は姿勢破綻の原因になるのでチェックを外して下さい。
魅力的な機能だとは思うので、むしろ正しい動作のさせかたを知っている人がいらっしゃいましたらコメントなどでお知らせ下さい……

ひとまず、自分とキャラクターの姿勢を追従させるために必要な準備は終わりました。

ここまでの設定で、VRコスプレは動くようになっているはずなので動作を確認してみましょう！
と言いたい所なのですが、ここで起動すると前述の通り顔ポリゴンの内側が見える状態でゲームが再生され、とても怖いことになると思います。
<b>(ハマりポイントその4)</b>

そこで、CameraRoot内の"CenterEyeAnchor"を顔の前に移動させましょう！
今回は、顔の前に向けてZ座標を0.1(10cm)移動させました。
しかしこれではCenterEyeAnchor自体を頭が追従してきているため、結局顔自体が前に出てきてしまい、原因解決になりません。
ここで、実際にVRIKに追従させている"CenterEyeAnchorDummy"のZ座標を-0.1します。
するとキャラの頭は元の位置に。カメラ自体は先程より相対的に前に出るため、問題が解決します。
言葉だけだとわかりにくいと思うので、図を用意しました。少しでも伝われば幸いです。
![ソリューション.png](https://qiita-image-store.s3.amazonaws.com/0/194196/b825c014-70e7-217b-7909-d22fe33ddcc4.png)

上記の設定が全て終われば、とりあえず好きなキャラになってVR内で動けるようになっていると思います！


#おわりに
初のQiita記事で初アドベントカレンダー参加させていただきました。
実際に書いてみると、チュートリアルを上げてくださっている皆さんには頭が上がりません……
この記事で一人でもVRコスプレ開発に参入してくださる方が増えれば嬉しいです！
間違いの指摘、ご意見やよりスマートな方法などございましたら、コメント欄かTwitter@karin_TSVRにお寄せいただければと思います。
ここまで読んでいただき、ありがとうございました！