🎨

ワールドによってQuestのアバターやパーティクル、ペンの色が黒くなるのを防ぐ

2024/02/22に公開

概要

VRChatのQuest(Mobile)対応アバター向けの記事です

Standard LiteのEmissionを利用して、明るさの下限を設定できるようにすることで、アバターの色がワールドのライトによって黒くなり過ぎるのを防ぎます

ワールドによってパーティクルやペン(Trail Renderer)の色が黒くなり過ぎてしまう問題もこの方法で解決できます

この方法をアバターに利用した例が以下の動画の一番右の状態になります。
https://x.com/Hyper_Mesh/status/1759888003231850575

環境

  • Unity 2019.4.31f1 (64-bit)
  • VRChat SDK - Base 3.4.2
  • VRChat SDK - Avatars 3.4.2

明るさの下限の設定方法

Quest版VRChatのリリース当初からQuest対応してくださっている & なんといっても可愛い、mio3io様制作の薄荷ちゃん(Quest版)を例に取り解説していきます
https://booth.pm/ja/items/2215270


  1. メッシュのマテリアルに割り当てられているShaderをStandard Liteに設定する

  1. 目的の「明るさ下限値」から「AlbedoのColor」と「EmissionのColor」のRGB値を設定する

明るさの下限値が0%だとEmissionを追加していない素のStandard Liteと同じ状態、
明るさの下限値が100%だとライティングによって全く暗くならないUnlitの状態になります

普段Standard Liteを使っている私的には、明るさの下限値は5~20%くらいが好きです

普段ToonLitを使っていて、Standard Lite特有の陰影をあまり出したくない方は50%などの高めの値を設定しても大丈夫です


明るさ下限値5%の場合の「AlbedoのColor」と「EmissionのColor」の設定例

コピー&ペースト用↓

明るさ下限値 [%] AlbedoのColorのRGB値 EmissionのColorのRGB値
0 1.000 0.000
5 0.977 0.256
10 0.953 0.351
15 0.929 0.422
20 0.904 0.481
25 0.877 0.533
30 0.850 0.579
35 0.822 0.621
40 0.793 0.659
45 0.762 0.696
50 0.730 0.730
55 0.696 0.762
60 0.659 0.793
65 0.621 0.822
70 0.579 0.850
75 0.533 0.877
80 0.481 0.904
85 0.422 0.929
90 0.351 0.953
95 0.256 0.977
100 0.000 1.000

効果確認

Directional Lightを非アクティブにした状態で、
UnityのWindowタブ → Rendering → Lighting Settingsを開き、
Environmentタブ → Environment Lighting項 → Intensity Multiplierの値を0にすることで、アバターの色が真っ黒になる環境を再現できます

最終的にはQuestやAndroidスマホなどのMobile環境で、ライティングの調整ができるアバターテストワールドや、実際にアバターの色が真っ黒になるワールドに行って確認することをお勧めします


VRChat Homeでパーティクル、ペンの色が黒くなった際の参考動画・画像
https://x.com/Hyper_Mesh/status/1778731931070599273

明るさの下限を設定する仕組み

私自身Shaderのことをちゃんと理解してないので、
間違ったことを書いているかもしれないことをご了承ください

ものすごく大雑把に説明すると、
Emissionが有効にされたStandard Liteで最終的に表示される色(RGB)は、
「Albedoから計算されたRGB」と「Emissionで計算されたRGB」が足し合わされた色です

「Albedoから計算されたRGB」はワールドのライトによって色が変化し、
「Emissionで計算されたRGB」はワールドのライトによって色は変化しません


Standard Liteで最終的に表示される色の内訳

VRChat標準のShaderの中身は
Packages\com.vrchat.base\Runtime\VRCSDK\Sample Assets\Shaders\ 内で確認できます


この記事の主題としているアバターの色が黒くなってしまう原因は、
下図のように「ライティング計算によって決まるRGBの係数」が0になっているためだと考えられます


そこで本手法では、Standard LiteにEmissionを追加し、
「AlbedoのColor」と「EmissionのColor」を上手に調節することで、

ワールドのライトの明るさが最大の場合は、素のStandard Liteと同じ結果になるように、
ワールドのライトの明るさが最低の場合は、Emissionの色が残るようにしています

上図からわかる通り、明るさの下限の設定方法の章で出てきた「明るさ下限値 [%]」は、ワールドのライトの明るさが最大の場合に出力される色の中に「Emissionで計算されるRGB」が占める割合になります


ここからまたややこしい話になるのですが、明るさの下限の設定方法の章の表を見てもらうと、明るさの下限値が50%であっても、「AlbedoのColor」と「EmissionのColor」のRGB値は0.5ではなく、0.730という中途半端な数字になっています

これは、標準のUnityやVRChatでは、リニアワークフローというカラーマネジメントが採用されており、カラーパレットで指定した色は、Shaderで処理される前に「sRGB色空間」から「リニア色空間」に色空間の変換が行われることに起因しています

例えば、
「sRGB色空間」から「リニア色空間」に色空間の変換が行われたShader内で、色の値が0.5になるようにしたければ、カラーパレットには0.5を1/2.2乗した0.730という値を設定しておく必要があります
(※色空間変換に近似式を利用した場合)

色空間やUnityのカラーマネジメントについては以下の記事が大変参考になるので、気になる方は一度読まれることをお勧めします
https://tech.cygames.co.jp/archives/2339/
https://r-ngtm.hatenablog.com/entry/2021/01/21/010643


以上のことを踏まえ、色空間変換に近似式を利用した場合の、
「明るさの下限値」から「AlbedoのColor」と「EmissionのColor」のRGB値を計算する計算式は以下のようになります

\def\sqr#1{#1^\text{\(\frac {1} {2.2}\)}} \ AlbedoのColorのRGB値 = \sqr{(1-明るさの下限値[-])}
\def\sqr#1{#1^\text{\(\frac {1} {2.2}\)}} \ EmissionのColorのRGB値 = \sqr{(明るさの下限値[-])}
\

実際に、明るさ下限値が5%の場合の「AlbedoのColor」と「EmissionのColor」のRGB値を計算してみます。5[%]は0.05[-]です

\def\sqr#1{#1^\text{\(\frac {1} {2.2}\)}} \ AlbedoのColorのRGB値 = \sqr{(1-0.05)} \ = 0.977
\def\sqr#1{#1^\text{\(\frac {1} {2.2}\)}} \ EmissionのColorのRGB値 = \sqr{0.05} \ = 0.256

Discussion