UE4でVR空間にカノジョを錬金 25日目

メリークリスマス！！

[UE4でVR空間にカノジョを錬金する Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ue4vrgame-create) 25日目、ついにUE4でVR空間にカノジョを錬金する Advent Calendar 2017ラストの記事です！

12/1～25日までに一人で、UE4を用いてサ○○レッスンとかVR○○ジョっぽいゲームを作って仮想彼女を生み出すことにチャレンジします。

ラスト、リップシンク実装の続きです。

ページの最後に25日時点での実装内容を、有料アセットを除いてソースをアップしていますので、もし気になる方がいればダウンロードしてみてください。

#FloatCurve

最初に全FloatCurveデータでやる共通設定を行います。

FloatCurveの全項目を選択し、コンスタント補間を押します。
すると以下の画像の通りになると思います。これを全FloatCurveデータに実施します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/3b362fa0-3075-85ad-1aa5-1106612fc8dc.png)

もし、最初が0から始まってない場合、時間0,値0のキーを打った後、コンスタント補間を実施してください。

#リップシンク　ロジック実装

リップシンクのロジック実装です。あらかじめユニティちゃんのBPにTagを付けます。
今回はUnityChanと名付けています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/d1a15561-7cbb-799f-ced7-38a36a8dbef2.png)

まずユニティちゃんのBluePrintクラスにカスタムイベントを作成します。
ここではPlayLipと名付けています。

全体処理は以下のような感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/53906117-ab12-32dc-2f5f-4c1b08899b30.png)

変数は以下の通りです。カスタムイベントで渡された各引数をこの変数にセットします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/f131a902-1417-b655-6b86-90772cadf048.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/93e365be-deeb-83ad-1be1-c9940babd7bf.png)

変数をセットしたらタイムラインを20秒で20を返すFloatを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/0e5a84ad-c939-e9c5-c4b9-35928616729a.png)
なぜ20秒なのかというと、再生するボイスデータが20秒を超えるものがないためです。

タイムラインをセット完了後、まずSetNewTimeでボイスデータのDurationをセットします。セット後、これをReverseで再生します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/5a095612-3ca3-00bc-a7fe-8f2314dad9a2.png)
タイムラインのUpdate経由で渡されるFloat値からボイスデータのDurationを引くことによって、現在の再生時間がわかるという仕組みです。

つづいてアニメーションBPに、リップシンク設定用の関数を作成します。これは外部で呼び出すのでPublicに設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/afb87146-b11c-9b6c-6eb7-af92f634f024.png)

上記関数をユニティちゃんBPから各モーフターゲット値のFloatCurveから取得してから関数の引数にセットします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/858081e2-de39-db49-92e9-d0e53a3e6674.png)

これでモーフターゲットのロジック実装が終了です。
最後にこれをGameManagerのBlueprintから呼び出します。

GameManagerに以下の関数を追加します。ボイス再生とリップシンク再生イベント通知を行う関数です。ユニティちゃんに設定したタグをここで利用してコンポーネントを呼び出しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/5ba14d2a-cae6-9064-18c1-ad1cbe7b9fbf.png)

イベントグラフにて、ボイスを再生していたところを全て上記の関数を呼び出すように修正します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/ede877f0-b482-a4e3-65f4-d9b495a34948.png)

全体としてはこのように実装しています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/104377/c4502371-e548-133d-69b3-2930b26b1ab6.png)

これでリップシンク実装は完了です！

# カノジョ錬金完了！

最低限一通り欲しい機能が実装できたので、早速動画に撮りました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">UE4でカノジョを錬金するアドカレ、完成品の動画<br>まだストアに出せるクオリティではないので、まだまだ改良してくけど、アドカレとしては完成ということで<br>今日のUE4なんでも勉強会のメインLTはこのVRのロジック実装を簡単に話します。　<a href="https://twitter.com/hashtag/ue4study?src=hash&amp;ref_src=twsrc%5Etfw">#ue4study</a> <a href="https://t.co/YmiqhrJNQi">pic.twitter.com/YmiqhrJNQi</a></p>&mdash; 荻野雄季 (@YuukiOgino) <a href="https://twitter.com/YuukiOgino/status/942904118632357889?ref_src=twsrc%5Etfw">2017年12月18日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

2日で作成した以下のプロトタイプに比べて、かなりカノジョが生き生きしているのを感じます。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">今回作ったものです。「クリスマスカノジョ」、例のアドカレのネタです<br>UE4で作りました。 色々と遅く始めたので作りが甘いのは仕方ないといいうことで <a href="https://twitter.com/hashtag/XRGJ?src=hash&amp;ref_src=twsrc%5Etfw">#XRGJ</a>　<a href="https://twitter.com/hashtag/XRGJGinza?src=hash&amp;ref_src=twsrc%5Etfw">#XRGJGinza</a>  <a href="https://twitter.com/hashtag/ue4?src=hash&amp;ref_src=twsrc%5Etfw">#ue4</a> <a href="https://t.co/fuaRsR6muc">pic.twitter.com/fuaRsR6muc</a></p>&mdash; 荻野雄季 (@YuukiOgino) <a href="https://twitter.com/YuukiOgino/status/934709537428221952?ref_src=twsrc%5Etfw">2017年11月26日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#これからの課題について

アドカレではこれで実装完了となりますが、ストアにリリースするには課題があります。

・FPSを90維持できていないのでCPU処理を見直す必要がある（重要）
→【最優先】90維持できないとストア審査に落ちるため
→最適化を入れていないため、解析ツールをみて処理負荷が高いところを修正していく
→必要ならマルチスレッドも検討にいれる

・チュートリアルが用意されてない（重要）
→【最優先】これがあるか否か、わかりやすいか否かでキーオンリー判定になる可能性があるため
→最初の選択肢でチュートリアルを入れる

・モデルに近づくと中身が見えてしまう
→判定用のコリジョンを用意し、近づいたらポストプロセスで画面を真っ黒にしてしまうとか

・表情が付いていない
→ボイス再生時にがんばって手付けするしか……

・手振りの実装できてない
→何かしらの形で手を振るアクションを入れたい

・アニメーションが基本動かない
→現状一つだけなので、ボイスにあわせてアニメーションポーズを切り替えてみようか……

・グレイちゃんがただのマスコットに
→ボイスも用意されているので、せっかくだからグレイちゃんルートも実装したい

・ニコニ立体ちゃんがただのマスコットに
→アニメーションのリターゲットに苦戦しているので、将来的に外すかも……

・キャラから視線をはずした時にボイスを言わせてみたい
視界を判定するロジックは実装できているので、これを応用した形で視線をはずしたときのボイスを再生されるように実装したい

#ソース公開

ソースは以下にアップロードしています。
https://github.com/YuukiOgino/ChristmasKanojo/tree/master

ユニティちゃんライセンスとグレイちゃんの利用規約を継承していますので、利用する際は必ず守ってください。

#まとめ
何とか書ききりました。完全に自己満足です。
昨年のリベンジが果たせてよかったです。

今年色々やりすぎて地獄しか見えなかったし、今回のでかなり満足したので、もう来年はやりませんｗ

・この内容は12/19に行われた「第2回UE4何でも勉強会 in 東京」のLTで先行公開しました。
<iframe src="//www.slideshare.net/slideshow/embed_code/key/qVukiuttUzVGid" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/YuukiOgino/ue4vrltthe-phantom-knowledge-project-for-ue4" title="UE4でVR空間にカノジョを錬金するLT+The Phantom Knowledge Project for UE4進捗報告" target="_blank">UE4でVR空間にカノジョを錬金するLT+The Phantom Knowledge Project for UE4進捗報告</a> </strong> from <strong><a href="https://www.slideshare.net/YuukiOgino" target="_blank">Yuuki Ogino</a></strong> </div>

以上でUE4でVR空間にカノジョを錬金する Advent Calendar 2017完走です！