webRTC 超低遅延化を目指して VRのサーバー処理(1)

スマホVRは、手軽で楽しいが処理能力の制約がある。また、360度映像の配信において、360度全ての映像を常に送り続ける必要はない。
つまり、見ている方向を検知してその部分だけの映像を遅れるようにすれば、映像のサイズも小さくなるので遅延が少なくなるはず！(配信側PCのCPUは上がると思うが)
全て、コンピューターでやって映像だけ送ってしまおう！
そうすれば超低遅延化できるはず！　という記事です。

最終的には1:Nにしようといろいろ調べていたが、なかなか大変そうなので、
とりあえず1:1を実装してみる。

記事がどんどん長くなっていくので小分けにする。
まとめ : [webRTC 超低遅延化を目指して VRのサーバー処理](https://qiita.com/kiyu_knowledges/items/25d15d0053bd44c32fbc)

#方法を探る
1:1で実現する方法は下記サイトに書かれていた。
[Unity+WebRTC+three.js+WebVRを使ってRICOH THETAの全天球画像を遠隔地のOculusでみる](https://qiita.com/mechamogera/items/ae283c651ae93cf76310) 

##どのアプリケーションを使うか
PC上で使うアプリに求められるポイントと考えられる（僕が使える）アプリをまとめる。

 - input : webカメラ入力が使えるか
 - processing : 360度映像のテクスチャマッピングができるか
 - output : どうすればバーチャルカメラをアプリ外へ出力できるか

| application | input | processing | output |
|:------------:|:-------:|:-----------:|:-------:|
| Unity | ○ |  ○ | syphon or [webRTC]((http://hammmm.hatenablog.com/entry/2018/03/03/233629)) |
| Blender | ○ |  ○ | ? |
| processing | ○ |  ○ | syphon |
| open frameworks | ○ |  ○ | syphon or [ycapture](http://izmiz.hateblo.jp/entry/2015/01/12/220133)(Windows) |

参考として、よくまとまっていたサイトのリンクをつけておいた。
アプリ内のカメラ映像を仮想カメラとして出力する方法などいろいろ調べて見たところ、こんな感じだった。

最初はUnityのwebRTCを試したのだが、エラーが出てビルドができなかった。

結局syphonを使用することにした。

#Unityからクライアントまで
#Unityで360度映像を表示する
参考サイトではThetaからの映像をUVC Blenderで変換してUnityに渡しているが、
今回は実験のため、CamTwistから360度映像ファイルをUnityへ配信する。

##Unityのダウンロード
###独り言
~~Unity何かに使うと思ってインストールはしているものの、使ったことない。。~~
Unityのバージョンは5.4.2だった。(2016年くらいにダウンロードしたのかな)
参考サイトではさらっといろいろ書かれているがUnity超初心者には辛い。
~~Unityアカウントとか忘れたわ~~
~~お、オフラインだったらログインしなくていいのか~~
sphere作成してたら突然落ちた。。。
めっちゃ重い&すぐ落ちる。
調べて見たらOS High Sierraとのトラブルはいくつか報告されていた。
ので最新版をインストールし直します。
Unityダウンロード時間かかる。。。家のWifiは弱い
ダウンロードが早いか、落ちる問題を解決する方が早いか。
たぶん原因はこれだと思う。
[High SierraおよびAPFSフォーマットMacで、SteamゲームやUnity Editorに不具合が確認される。](https://applech2.com/archives/20170930-apfs-issue-steam-and-unity-games.html)
アップデートするしかない。
5時間くらいかけて2018.2.4f1をインストールできた笑
安定してそう！

##sphereに360度映像を貼り付ける
さっそく進めていく。
[【THETA V】ライブストリーミングの映像をUnityで表示](https://qiita.com/mo4_9/items/c21cba8228fbeb7c2bb0)

 - sphere作成
 - sphereのスケールを100倍に
    - ヒエラルキーにD&D
        - ああ、ドラッグ&ドロップか
 - sphereにスクリプトを追加
    - ヒエラルキーでsphereを選択して、Inspector/Add Component/new script
    - ファイル名を`WebCamDrawer`に設定
    - Projectパネル/Assetsにファイルができる。
    - 自分の好きなエディタで開く
        - [Unity付属のMonodevelop以外でコーディングをする](https://qiita.com/niwatori/items/a862d50cf61f45d77dba)
    - 参考元のソースをコピペ
        - deviceNameKeywordをCamTwistに変更
 - shaderにUnlitを設定
    - [【Unity】シェーダ入門](http://baba-s.hatenablog.com/entry/2018/01/09/090000)
 - 再生ボタンを押す

CamTwist経由の360度映像がうまく球面に貼り付けられてることが確認できた！
しかし、このままだとsphere内部にカメラをおいた時にsphereがレンダリングされない
ので、以下の手順に従ってシェダーの設定を変更した。
[Sphereモデルを天球として利用するシェーダー](https://qiita.com/ELIXIR/items/a5988ca21f38fabca7b0)

これで、内部でもレンダリングされる。

#Unity内部のカメラ映像をsyphon経由で出力する
このあたりを参考にして進めた。
[Syphonを使ってUnityの絵をTouchDesignerに送る(macOS)](https://qiita.com/sada_lp1/items/c892aeb3462b86bcd469)
[Create a Virtual Webcam for your Syphon Client with CamTwist](http://tobystereo.com/2014/06/create-a-virtual-webcam-for-your-syphon-client-with-camtwist/)

##問題
これで、CamTwistまで映像を送れるはず。
問題はCamTwistを二回経由しないといけない事。
360video → CamTwist(1) → Unity → syphon → CamTwist(2) → 配信用ブラウザ

CamTwistは出力が1つしかできないため、
のちのち1:Nにすることを考えたらCamTwist(2)をなんとかする方法を考えるのが良さそう。
で、調べたがなかなか険しい。
時間がかかりそうなので、とりあえず力技でCamTwistをコピーしてCamTwistを同時に2つ立ち上げておく。

これを[前回](https://qiita.com/kiyu_knowledges/items/2685d1f9323221ac335c)作ったwebRTCの配信ブラウザで読み込む。

CamTwistの切り替えができなかった。。。。
という事で、テストなので360度ビデオを直接Unity内で再生することにする。
##改善
これを参考に360度映像をUnity内部で再生できるようにする。
[unity2017.3でskyboxで360度映像を流す。](http://bibinbaleo.hatenablog.com/entry/2017/12/20/184828)
このサイトに沿ってつまづいたところだけピックアップ

 - 使用したUnity2018.2.4f1はデフォルトで`skybox/Panoramic`シェダーが入っていた。
 - ビデオファイルをassetsにD&D後、ヒエラルキーにD&D
 - skyboxの設定場所は`Window/Rendering/Lightning`


Unityがバックグラウンドでも動くようにRun In Backgroundを設定
`Edit/Project Settings/Player Settings/Resolution and Presentation`

これで視聴用ブラウザまで映像を届けられる。
Unity → syphon → CamTwist → 配信用ブラウザ → 視聴用ブラウザ

テスト成功！
Unityを停止するとCamTwistのsyphon設定が初期値に戻ってしまうがしょうがない。
<img width="1280" alt="flow.png" src="https://qiita-image-store.s3.amazonaws.com/0/281453/abe5fe1e-8791-f1d0-2f38-e27d985a716a.png">

#まとめ
とりあえずUnityからクライアントまでつながりました！
今後双方向通信を実装していきます！