2019年6月末でサービスを終了した『Readyyy!』。その『Readyyy!』にテクニカルアーティストとして参加していましたセガゲームスの宮下です。『Readyyy!』をプレイしてくださった皆様、本当にありがとうございました。
また、社内はもちろん、大勢の社外の方々のお力添えでリリースした『Readyyy!』でしたが、アプリのサービスを早々に終了させる結果になってしまったこと、誠に申し訳ありませんでした。スタッフ一同一丸となって取り組みましたが、力及びませんでした。
そんな中『Readyyy!』をプレイしていただき、サービス終了を惜しんでくださる皆様からは、厳しいご意見をはじめ、心温まるお手紙、想いの詰まった色紙などをいただきました。皆様のお声は開発チームまでちゃんと届いており、スタッフ一同ありがたく読ませていただいております。そして、そのような𠮟咤激励のお声にどう応えていくのか、日々考えながら業務に励んでおります。
テクニカルアーティストの自分と致しましては、『Readyyy!』の開発を通じて得た知見や技術を、この「セガテックブログ」の場で伝え、そして楽しんでいただくことで、皆様からのお声に少しでも応えられたらと思い、このブログを書かせていただきました。
今回『Readyyy!』でのLive2D活用事例として2つご紹介します。
1つはライティング表現で、主にその仕組みやテクスチャの使い方に関する内容です。すでにプレイできなくなっているアプリの画面などを用いての説明となってしまい、重ね重ね申し訳ありません。
もう1つは、今後も『Readyyy!』のアイドルたちの姿を届けられることになったコンテンツ、多人数の同時生配信についてです。こちらは、多人数同時生配信の仕組みと、それを作り上げていくスタッフとのやりとりの様子をお伝えします。もしかするとその当時のやりとりで気になるところもあるかもしれませんが、お付き合いいただけますと幸いです。
それでは、始めさせていただきます。
Live2D®とは?
Live2Dとは、元のイメージを保ったままイラストを動かしたり、疑似的に3Dのように見せられる特徴を持つ、株式会社Live2D*1が開発した技術やソフト、データのことです。ソフトの正式名称は「Live2D Cubism」と言います。「Cubism SDK 3.0*2」でUnity*3からLive2Dへのアクセス方法が一新されたのですが、柔軟性が高くとても良い出来だったので『Readyyy!』で採用することに決めました。ただし「Live2D Cubisim」と「Cubism SDK 3.0」だけではライティングの実現には足りていません。新たなシェーダーとコンポーネント*4の開発、それを活用するための特別なデータが必要でした。
Live2Dライティング表現のあれこれ
『Readyyy!』のLive2Dでのライティング表現が一部で話題*5になっていましたが、開発初期にプロトタイプを部内で紹介したときも、驚きの声とともに「力技?!」という声があがりました。そのときは「力技とは心外だな」と内心ふくれていたのですが、いまにして思えば…まあ力技ですね。やっていることは単純なんです。
それでは、『Readyyy!』のアイドルの1人、上條雅楽(かみじょううた)君に手伝ってもらって、ライティングの仕組みを説明していきます。
使っているテクスチャについて
ライティングを実現するために、1ポリゴンにつき3つのテクスチャを使ってます。具体的には、アルベドマップ(色)、シャドウマップ(影)、スペキュラマップ(光沢)です。
「Live2D Cubism」はマルチテクスチャに対応していないので、この3つのテクスチャを生成するために、3回の出力作業が必要ですが、この面倒な作業はSikuliX*6を使ってほぼ自動化しています。UV座標はLive2Dのものをそのまま利用して、ライティングの主な処理はUnity上のシェーダーで行っています。
アルベドマップ
まず、体と顔のアルベドマップが1枚ずつ、計2枚あります。画像サイズは1024x1024ピクセルと600x600ピクセル*7で、フォーマットはRGBA Crunched ETC2を使っています。これはUnity2017.3から導入されたフォーマットで、ストレージの消費量削減に抜群の効果があります。それまでは、JPEGファイルをダイレクトに使う計画で、その場合だと、RAMへの展開後にTrueColorになってしまい、メモリ消費量も膨大だったので、このフォーマットには助けられました。
なおRGBA Crunched ETC2はノイズが目立つので、軽減するようにアルベドマップのサイズは比較的大きめにしてあります。ノイズの軽減については、またあとで説明しますね。
シャドウマップとスペキュラマップ
続いて、シャドウマップとスペキュラマップです。
シャドウマップとスペキュラマップに関しては、グレースケールで、かつ、ちょうど合計4枚なので、劣化しないTrueColorフォーマットを使ってRGBAチャンネルにパッキングしています。先ほども言いましたが、TrueColorだとメモリ消費が大きいので、画像サイズをぎりぎりの380x380ピクセルまで下げています。ETC2フォーマットで圧縮したケースも試してみましたが、見栄えが悪かったので不採用にしました。
陰影のバリエーションについて
ちょっとややこしいのですが、アイドル1ポーズにつき、シャドウマップとスペキュラマップをそれぞれ3種類用意しています(下の画像の左から、逆光、左順光、右順光)。これは太陽や照明の位置の違いを表現するためで、このバリエーションはライティングの効果を発揮するための大切な部分です。なぜなら、これが1種類しかないと、この一連の仕組みはあまり意味がなくなってしまうからです。
テクスチャの種類のまとめ
マップの種類 | 画像サイズ | 作業上の枚数 | 実際の枚数 | 画像 |
---|---|---|---|---|
アルベド | 1024x1024 | 2 | 2 | |
シャドウ、スペキュラ | 380x380 | 2x3、2x3 | 3 |
ここまでの説明を表にまとめてみました。つまり1ポーズあたり5枚のテクスチャが必要ということです。なお『Readyyy!』では、アイドル1人に対してポーズを7種類用意する予定でした。また衣装差分は5種類あるため、5x7x5で合計175枚のテクスチャが1人あたりに必要となります。なかなかのボリュームですね。
シャドウマップとスペキュラマップの縮小
少し話を戻します。シャドウマップとスペキュラマップの画像サイズを下げた(380x380ピクセル、下の画像の左)ということは、アルベドマップ(1024x1024ピクセル)と比較して、相当ぼけているということなんですが、思いの外うまくなじんでいます。それどころか、64x64ピクセルまで縮小しても破綻しないんですね。
解像度を下げても破綻しないというのは、いわゆる3Dのシャドウマップと似ていますね。
ノイズ軽減のためアルベドが大きめという理由もあるのですが、シャドウマップとスペキュラマップはアルベドマップと同じサイズであるべきという固定観念にとらわれていたので、個人的にこの発見は大きいものでした。
アートディレクターからのチェックで、縮小は380x380ピクセルで止めたのですが、曇り空のときは、右の64x64ピクセルバージョンを使うように提案してみてもおもしろかったですね。
シェーダーでレイヤー合成
シェーダー上で、先ほどのアルベドマップとシャドウマップを乗算し、スペキュラマップを加算してライティングを実現しています。
fixed4 main_tex = tex2D(_MainTex, IN.texcoord); fixed4 packed_tex = tex2D(_PackedTex, IN.texcoord); fixed3 albedo = main_tex.rgb; fixed3 shadow = packed_tex.rrr; fixed3 specular = packed_tex.ggg; // 計算を省略しています! fixed3 clr = albedo * lerp( IN.ambient, fixed3(1,1,1), shadow ) + specular; return fixed4( clr.rgb, main_tex.a );
Photoshopのレイヤー合成みたいなことをシェーダーでやっているわけですね。
また、 影の色味の違いを表現するために、頂点カラーを利用しています。頂点カラーは「Live2D Cubisim」上で直接設定可能なのですが、ヒューマンエラーが発生しそうなので、ノード名に特定のキーワードを入れてもらって、Unityでのインポート時に、自動的にキーワードから頂点カラーを設定するようにしました。ただし、間接的な方法を採用したことで「Live2D Cubism」上で色を視認できないという弊害が発生してしまい、肌なのに服のキーワードになっているなどの設定ミスが多発することになりました。チェックにも修正にも結構時間がかかってしまったので、この方法は、もっと検討改良すべきでした。
髪の毛(赤色)、肌(緑色)、服とヘッドセット(青色)として設定していますが、この色をダイレクトに乗算しているわけではありません。
あくまで質感の種類を識別するために使っていて、このようなシェーダーコードにしています。
ambient = _HairAmbient*v.color.r + _SkinAmbient*v.color.g + _ClothAmbient*v.color.b;
本来質感が異なる場合は、マテリアルを分けて表現しますが、今回はドローコール数を増やしたくないため、このような仕組みにしています。
桜や建物などの落ち影
Live2Dへの落ち影は、かなり反響があったので、うれしかったですね。桜や建物の落ち影用のテクスチャは、必要な背景にだけ用意しており、スクリーン座標系を使ってシェーダーで計算しています。
スクリーン座標系はUV座標系よりも単純で、シェーダーでよく使うテクニックです。Live2Dに対して、落ち影テクスチャをプロジェクションマッピングしているといったほうがわかりやすいかもしれません。
『Readyyy!』では、Live2Dを半透明化させて消すときに、一時的にレンダーテクスチャを使っています。そのときにスクリーン座標系が画面全体ではなくレンダーテクスチャの大きさのものに変化にしてしまうため、同じ計算方法のままだと、落ち影がずれてしまうのです。その問題に対応するために、少し面倒な計算になっています。
half4 screenPos = ComputeScreenPos(OUT.position); half2 uv2 = screenPos.xy / screenPos.w; // _ViewportScaleX等は、CPU側で計算している uv2.x = uv2.x * _ViewportScaleX + _ViewportOffsetX; uv2.y = uv2.y * _ViewportScaleY + _ViewportOffsetY;
言い忘れていましたが、背景ごとのライティング用パラメーターの設定は、手動で行っています。
逆光陰影のクオリティアップ
もともと逆光陰影は1段階でした。下は2段階と1段階の比較画像です。
1段階のものでは物足りなさを感じていたので、順光時の陰影とブレンドして陰影を2段階とする手法を提案し承認されました。手作業でテクスチャをブレンドするのは面倒なので、スクリプト言語のRuby*8とRMagick*9という画像処理ライブラリで自動化しました。
そういえば、最近、RMagickのメモリ使用量を減らしたという素晴らしい記事を見つけまして、一人で大興奮していました。RMagickのメモリリークには、苦労させられていたので!ありがとうございます!うれしさのあまり、テクニカルアーティストの同僚たちにもチャットで共有したのですが、特に反応はありませんでした。テクニカルアーティストの使うスクリプト言語は主にPython*10ですから、まあそりゃそうですよね。
RGBA Crunched ETC2のノイズ軽減について
RGBA Crunched ETC2のストレージ上での圧縮性能はとても高いのですが、そのかわりノイズが発生します。このノイズに対抗するには、テクスチャを大きくすればいいのですが、比例してRAMとストレージの消費量も増えるので、それとクオリティとを天秤にかけることになります。『Readyyy!』ではLive2Dのテクスチャの他に、フォトにもこのテクニック(大きくするだけなんですが!)を使っています。
フォトとはガチャで引くことのできる、アイドルの写真のことです。
『Readyyy!』は画面サイズ1334x750ピクセルの想定で作っているので、画面サイズに近い1336(4の倍数)、画面サイズを大きく超えた2048、4096ピクセルの3種類のフォト用の画像で、ノイズがどのように変化するか比較してみました。
横幅(ピクセル) | RAM(MB) | ストレージ(MB) | フィット後に切り抜いた一部画像 |
1336 | 4 | 4 | (参考データ)TrueColorだった場合 |
1336 | 1.2 | 0.2 | |
2048 | 2.8 | 0.45 | |
4096 | 12 | 1.3 |
上は、1334x750ピクセルの画面サイズにフィットさせて、一部分を切り抜いた画像と容量の表です。4096ピクセルのものが一番きれいですが『Readyyy!』ではバランスを取って2048ピクセルのものを採用しました。
ここで「フォトにはアルファチャンネルがなさそうなのに、なぜRGBA Crunched ETC2フォーマットを使うのか?」という疑問をもつ方がいるでしょう。その理由はiOSとAndroid両方で有効なCrunchedなフォーマットがRGBA Crunched ETC2しかないからです。ですから実はアルファチャンネル分、無駄にRAMを使っているのですが、それを踏まえてもストレージ上での圧縮性能が魅力的ということなのです。
最後のは少し余談でしたが、Live2Dのライティング表現については、以上です!
つづいて「多人数による同時生配信」に話を移しましょう。
多人数による同時生配信
IPプロデューサーのOさんから、生配信の相談は突然やってきました。
「2月14日のバレンタインデーに、アイドル2人で生配信をやりたい!」
2人同時に生配信するには、リアルタイムでアイドル2人の映像を生成して、配信サービスを提供しているSHOWROOMさんのサーバーに転送する必要があります。私がLive2Dのデータ組み込みやライティングを含めた実装まわりを担当していたので、引き受けることになりました。
ところで、この生配信の見た目って何かに似ています。そう『Readyyy!』のアドベンチャーパートです。
事前に収録した音声を使っているのと、スクリプターさんが、あらかじめ設定したポーズを表示している点が異なりますが、要するに、この生配信というのは『Readyyy!』のアドベンチャーパートのようなものをリアルタイムで生成しようという試みなんです。
アイドル1人での生配信は、SHOWROOMさんのスマホアプリ「SHOWROOM V」で確立されていましたが、2人の仕組みは備わっていなかったので、セガ側で用意する必要がありました。
そのときは配信日までの時間と生配信に関する知識が不足していて、とても間に合わせる自信がなかったので、Oさんとの相談の結果、1か月後の「3月14日のホワイトデー」までに2人同時生配信の仕組みを用意する、ということになりました。リハーサルのことを考慮するとその1週間ぐらい前が締め切りですね。
ところで、Live2Dをバーチャルキャラクターとして操作するツールというと、「FaceRig」が有名ですね。
『Readyyy!』のLive2Dは、アイドル1人に対して7種類のポーズがあるのですが、これは「FaceRig」でいうところのアバターが7種類あるという意味になります。ネットの情報を調べた限りでは「FaceRig」は多機能なんですが、生配信中に7つのアバターを切り替えていくやり方には向いていないと判断し(もし問題なくできるとしたらごめんなさい!)、Unityで簡易的なアプリを作ることにしました。
2人同時生配信の誕生
こうして会社のヘッドセットを借りての検証と開発の日々が始まりました。自席でマイクに向かって声を出す恥ずかしさと言ったら…。なので人が少なくなった夜中に声を出したり、会議室を取ってそこで検証したり、いろんな人に「これって、もはやテクニカルアーティストの仕事じゃないよね…。」とも言われたり。褒め言葉と解釈しましたが。
通常バーチャルキャラクターといえば、カメラによる顔認識などで実際の動きをトレースして、キャラに反映するものですが、今回は割り切ってウェブカメラは使わずに、インタラクティブなものはマイクから入力された声の音量による口パクの動きのみ。体の動きはキーボードの操作でポーズやアニメーションを切り替えるだけ、例えば「1」を押すと喜んでいるポーズ、「2」を押すと悲しんでいるポーズになる、というような何ともレトロな仕組みにしました。
FaceRigの代わりになるUniyアプリはできたので、次は2人同時の部分をどう実現するかです。
参考にしたのがこのサイトです。
なるほど。2人目は「Skype」や「Discard」でビデオ通話して、そこからキャプチャしているんですね。しかし今回の場合、すぐそばに2台のノートPCがあるのに、わざわざネットワークを介してビデオ通話というのは、ちょっと大げさすぎますし、無意味に遅延が発生してしまいますよね。
数日、他の仕事しながらぼんやり考えた結果「ネットワークの代わりにHDMIを使うアイデア」にたどり着きました。
- 市販のキャプチャボックスを使って2台のノートPCを、HDMIとUSBでつなぐ。
- ヘッドセットをノートPCにつなぐ。普通のマイクでも可。
- それぞれでUnityアプリを立ち上げて、アイドルが映った状態にする。
- 下記図の左側のノートPCから、右側のノートPCに画面を転送する。右側のノートPCにはUnityアプリの画面が2つ映った状態になる。
- 右側のノートPCのOBS*11上で、2人のアイドルをクロマキー合成する。
- OBSからSHOWROOMさんのサーバーに転送する。
この方法で、2人同時生配信を実現できました!
ただし、HDMIを使う方法には2つ問題がありました。
問題の1つは、HDMIでの動画と音声の転送の遅延です。これにより相互のマイクで音声を拾った場合に、遅延した音声も合わせて配信されてエコーがかかったような現象が発生しました。
もう1つは、HDMIでPC同士を接続することの不安定さです。なかなか認識しなくて、何度もHDMIを抜き差しして、やっと成功する…といった具合で、本番の配信中に接続が切れないかと心配でした。
結局未解決のまま生配信したのですが、そのときダイジェストがこちらです。
なんとかそれっぽくなりましたね。
なお、機材のセットアップや生配信中のOBSの操作、トラブル対応のため本番は毎回立ち会っています。
5人同時生配信への道
この段階では、Oさんには「同時に生配信できる人数は2人までですからっ」とクギを刺していました。
ところが、その後この仕組みを使ってユニットごとに「新曲発表」の生配信をするという企画が立ち上がりました。それも、そのユニットのメンバー全員(2人〜5人)で、です。
新曲発表1組目は「La-Veritta(ラヴェリッタ)」という2人組のユニットだったので、トラブル*12もありましたが、そのままの仕組みで乗り切れました。
2組目の「Just 4U(ジャストフォーユー)」という4人組ユニットのときは、Oさんの提案で、2人ずつ入れ替わりで生配信しました。結果、トラブルもなく大成功でしたが、でも私は負けた気がしたのです。そのときの視聴者の書き込みからもメンバー4人全員がそろっている姿を見たいという気持ちを感じましたし、なにより、できない理由が技術的な事情というところに、敗北感を覚えました。
このままではつまらない。『Readyyy!』で一番人数の多いユニット「SP!CA(スピカ)」は5人組なので、5人同時生配信の仕組みを作ってやる、と心に決めました。
単純に5台のPCをHDMIでつなげば、今の仕組みのまま対応できるかもしれません。ただPCが2台のときでさえ多少不安定なのに、5台だなんてとんでもない…。トラブルが発生することは容易に想像できます。
そんなことをぼやいていたら、いつもお世話になっているインフラ屋のAさんの助言がヒントになりました。
Aさん「1台で完結させればいいんじゃない?」
Aさんも深い意味で言ったわけではなかったと思うのですが、理にかなっています。1台…そうか…できるかも…。
PC1台で5人同時生配信を行う仕組みはこうなりました。まず以下の機材を用意します。
- デスクトップPC1台
- USB接続のマイク5本
- USB接続のコントローラー5台(実は4台でよかった)
- 液晶モニター2台
- USBハブ2個
- Live2Dのアイドルを表示する自作Unityアプリ
- 使用するマイクやコントローラーを切り替える機能
- マイクからの音量に合わせてアイドルが口パクする機能
- アイドルを切り替える機能
- コントローラーでアイドルのポーズを切り替える機能
- OBS
セットアップの手順はこうです。
- PCにマイクとコントローラーを5台ずつ、つなぎます。
- そのPCで自作Unityアプリを5つ*13立ち上げます。
- Unityアプリ上で、それぞれ、アイドル、マイク、コントローラーの設定をします。
- OBSでUnityアプリの画面をすべて取り込んで、クロマキー合成します。
- OBSからSHOWROOMさんのサーバーへ転送。
これだけの機材の数になると、セットアップの手間もかなりのものになったのですが、その苦労の甲斐あってか、5人同時生配信の野望を達成できました!また、PCが1台になったことで遅延の問題も解決して一石二鳥です。
『Readyyy!』のアプリでは、パフォーマンスの都合上、アイドルの同時表示数を3人に制限していたので、ある意味で「生配信はアプリを超えた!」とも言えます。
ツイッター上でも5人全員そろっていることへの驚きの反応があったので、うれしかったですね。ちなみに明るさが人によって異なっているのは、話している人が誰かをわかりやすくするためです。
では次に、5人同時生配信をする上で遭遇したトラブルを3つ紹介します。
マイクデバイスを選択できない問題
Unity2017.4では、複数マイクデバイスから任意の1つを選択できないバグがあり、どう解決するか悩まされましたが、そのバグが修正されたUnity2018.2を使うことで、あっさり解決しました。直っててよかったです…。
バックグラウンドのUnityアプリでは、コントローラーが反応しない
Unityアプリを5つ立ち上げるので、すべてのアプリをアクティブにしておくことはできません。そのためUnityアプリがバックグラウンドの状態でも、操作できるようにしておく必要があります。
このサイトを参考にXInputを使って解決したまではよかったのですが、リハーサルで、5台目のコンローラーがまったく反応しないトラブルに遭遇しました。ネットで調べてみると、XInputはコントローラーを4台までしかサポートしていないそうで。そのためUnityアプリを修正して、5人目はキーボードでポーズを切り替えるようにしました。キーボードでの操作は2人同時生配信のときに実装していたので、対応自体はスムーズでしたが、まさかそんな落とし穴があるとは…。でも、プログラマのK君に聞いたら常識のようでした。
しゃべっていないアイドルが口パクをしてしまう
指向性のマイクを用意したのですが、それでもマイク同士が近いため、他のメンバーの声を拾ってしまい、しゃべってないアイドルが口パクをしてしまう問題が発生しました。超指向性のマイクを導入する方法もありましたが、今回はコントローラーの右トリガーを引いたときにのみ口パクをするようにプログラムを修正しました。ちょっとかっこ悪い解決方法ですね。
先ほど紹介した2人同時配信のダイジェスト動画もよく見ると、右側のアイドル(全)の口が時々、左側のアイドル(淳之介)につられて動いているのが分かります。
多人数生配信のまとめ
生配信の仕組み作りについては、世間のVTuberさんにとっては目新しいことはなかったと思いますが(結果的に)遅延のない5人同時生配信の試みはちょっとおもしろかったんじゃないでしょうか?条件は異なりますが「FaceRig」のマルチアバター機能も4人までみたいですし。
生配信自体、まったく新しいチャレンジだったので、プレッシャーがありながらも「SP!CA」5人全員を登場させることができたときは、達成感ありました(疲労感も…)。また、生配信中にトラブルがよく発生するので、臨機応変で、かつ、一か八かの対応も、普段のゲーム開発では味わえないスリリングさがありました。あと、OBSというツールがほんとよく出来ています。
最後に…
『Readyyy!』でのLive2D活用事例、いかがだったでしょうか?今後も「応援し続けてよかった」と思えるくらい楽しんでいただけるよう、アイドルの生配信をはじめとするさまざまな可能性に、『Readyyy!』に関係するスタッフ一丸となって取り組んでいきます。
この記事が、皆様のモチベーションに少しでもプラスの影響を与えることができたのなら、幸いです。
©SEGA
*2:UnityでLive2Dを扱うためのプログラム https://live2d.github.io/#unity
*3:ゲームを作るための統合開発環境 https://unity.com/ja
*4:特定の機能を持たせたプログラムのかたまり
*5:https://togetter.com/li/1316881
*6:http://sikulix.com/ GUI上での操作をRubyやPythonで自動化するツール。
*7:ETC2は2のべき乗ではなく4の倍数でOK
*8:まつもとゆきひろ氏が開発した、個人的に大好きなスクリプト言語。テクニカルアーティストにはどちらかというと人気はない。
*9:画像処理ライブラリImageMagickのRubyインターフェス。Rubyで簡単に画像を処理できるようになる。
*10:Mayaをはじめ多くのツールに組み込まれているスクリプト言語。DeepLearningでも良く使われている。テクニカルアーティストに大人気。
*11:正式には「OBS Studio」という。生配信で使われるオープンフリーなソフトウェアのこと。
*12:1人の声が突然ロボットみたいな声になるというトラブルが発生し、めちゃくちゃ焦りましたが、Unityアプリを再起動したら直った。
*13:1アプリで5人表示させる方法もアリかもしれませんが、生配信中にアイドルの数を増減させる演出をすることがあり、別々のアプリにしておいてOBSで人数を管理する方法がやりやすかった。