VRChat 用のアバタのアップロードで詰まったところ

ようやく自分の 3D モデルが完成し VRChat デビューを果たし,そしてユーザのランクが上がってアバタがアップロードできるようになりました. しかし,Unity 上では正しく見えているにもかかわらず万を辞してアップロードしたアバタが VRChat 上でおかしく見えるという問題に直面しました. 自分が躓いた問題と,その解決について記しておきます.

環境

本環境は 2020 年 8 月 18 日における VRChat 環境で,Avater 3.0 の 2020.05.06.12.14 を用いたものです. また,Unity は 2018.4.20f1 を利用しています.

Unity 上では確かめたはずなのに

Unity 上では正しく動いているのに,VRChat に持っていくとおかしくなる,という問題がたくさん発生しており,解決に結構な手間が必要でした. このページに書かれている問題はそのような,「Unity の Sample Scene では一見問題なさそうなのに,VRChat に持っていったらおかしくなった」 というものです.

自分でなかなか気づけない問題がある

特に,アバタで発生する一部の問題は,自分自身でなかなか気づくことができませんでした. 念入りに調整して確認したはずなのに,他の人から指摘されて気が付く,という事が多発していました. 以下の三つの問題は,「自分の環境では発生せず,他人から見たときだけおかしい」という厄介な問題でした.

  • 目の向きがおかしい
  • 髪の毛のボーンが置いてけぼりになる
  • シェーダの一部機能が勝手に実行されている

また,「反射が明らかにまぶしすぎる」の問題は,デフォルトのホームのワールドでは発生しない問題でした.

アバタの設定に関する問題

目や顎の向きがおかしい

問題

目の向きが 90 度や 180 度ずれており,変な見た目になっている. または,顎が開きっぱなしになっている.

ただし,ボーンの roll は 0 になっており,かつ Unity 上で実行しても問題はない.

原因

どうやら,VRChat 上では Humanoid に対する処理と表情に対する処理が重複して行われてしまっているようです. そのため,Humanoid の設定に目や顎のボーンが設定されていると,変な挙動を示すようでした.

私のアバタでは,目の異常が自分で見えなかったためなかなか発見が遅れてしまいました. ただし,自分自身の映像でも,expression から reset avatar を実行すると挙動がおかしい表示に切り替わっていました.

解決手法

/images/2020/2020-08-19-013323.png

Humanoid の設定

Humanoid の設定から,Left EyeRight EyeJaw の設定を外しました.

また,効果があるのかはわかりませんでしたが,ローテーションが (0, 0, 0) の状態で目が正面を向くように設定しました.

一部のボーンが置いてけぼりになる

問題

Connected に設定されているはずの髪の毛のボーンが,なぜか途中からアバタの移動に追従せず取り残される. ただし,他人の視点でしか発生せず,自分からは正常に見える.

解決手法

なぜかわかりませんが,誤って Dynamic Bone と Rigid Body が同じボーンに適用されていたものを削除し Dynamic Bone のみにしたら直りました.

アバタの設定変更がすぐに反映されない

問題

他人から指摘された箇所を修正したはずなのに,まだ直っていないといわれる

原因

VRChat では,ワールドに訪れたアバタはすべてメモリにキャッシュされているようです. そのため,「別の人に確認してもらいながら試行錯誤する」という流れを困難にしています. 相手が,つまり自分のアバタを見る他のユーザが一旦ワールドを抜けない限り,アバタを更新しても問題は出続けてしまいます.

特に自分では確認できない問題や,一部の人しか発生しない問題を修正しているときには非常に不安になりますね…….

解決手法

同一アバタの判別は Blueprint ID を元に行われてます. 単純に再アップロードしてアバタを更新するのではなく,一旦削除して別のアバタとしてアップロードすることで解決できます.

シェーダに起因する問題

反射が明らかにまぶしすぎる

問題

屋外のような明かりが強いワールドに行くと,強烈な反射が出てきてしまう.

/images/2020/VRChat_1.png

まぶしい反射がちらちらと写っている

原因

私の書いたシェーダでは,Phong 反射(光沢のある物質の表面にでてくるスポット的な反射)の処理をフラグメントシェーダの最後に追加しています. ここの処理は既存の値に足し算しただけにしていたため,値が 1 を超過することがありました.

1 ですでに真っ白となるため 1 を超える値も意味はなさそうに感じますが,実際には HDR として「非常に明るい光」に解釈されるようです. つまり,1 を超過した場合はフラッシュのような周囲に光が伝搬する効果が生まれてしまい,大変まぶしい見た目になってしまうことがあります.

この問題は,強い光を浴びないワールドでは発生せず,ホームのワールドも発生していませんでした.

解決手法

フラグメントシェーダで最後に値を返す前に saturate() 関数を用い,色の値が 1 を超えないようにしました.

シェーダの一部機能が勝手に実行されている

問題

大人数がいるワールドにおいて,シェーダの中で on/off を切り替えられるような機能があるときに,使っていないはずの(off にしてあるはずの)機能が勝手にオンになっていて見た目がおかしくなることがある.

ただし,自分では確認できない.

原因

シェーダで if 文を用いた分岐処理はコストが高いことから,プリプロセッサ命令で分岐することが多くあります.

このとき,マテリアルの設定画面でチェックボックスを用いて変更できるようにしたときは #pragma shader_feature YOUR_KEYWORD のような記述をして利用します. 特に複雑な設定が可能な大規模なシェーダはこれが多用されています. 有名どころではユニティちゃんトゥーンシェーダもそうですね.

しかし,ここで用いられるキーワードの数は Unity 全体で 256 個までと制限されています. VRChat SDK の記述によれば,Unity 自体がすでに 60 近く使っているようです.

/images/2020/2020-08-23-040105.png

Shade Keyword が使用されているという警告が表示される

/images/2020/2020-08-19-002828.png

Shader Keyword Utility に説明が書かれている

この問題のやっかいなところは,どうやらこのキーワードのリストは読み込んだ順に処理され,上限に達した後に読み込まれたものから発生する挙動をしていることです. つまり,自分自身は当然最初に読み込まれるため気づくことはありません. 別のユーザから確かめてもらっても,そのワールドでキーワードがたくさん使われていなければ発症しないため,数人しかいないような空間でもまず発症しません. そして,発症するぐらい人が多くても,見ているユーザによっては症状が出たり出なかったりします. このことが確認を困難にしています.

解決手法

この問題は,シェーダキーワードが一つでも使用されていれば発生しうる問題です. 唯一の解決方法は,シェーダからキーワードを用いた分岐をすべて手で除去することです. マテリアルによって設定が異なる場合は,シェーダファイルが複数必要になります. if 文を用いた分岐に置き換えることでも対応ができますが,あまり好ましくはありません.

なお,シェーダの設定項目によっては,機能がオンになっていても初期設定では見た目が変化しないということもあります. ただし,余分な処理が実行されいてるため,負荷が増大することには留意する必要があります. また,幸いながらユニティちゃんトゥーンシェーダのような有名どころのシェーダは利用者が多くリストが埋まる前に読み込まれる可能性が高いのか,それほど問題にはなっていないような雰囲気です.