こんにちは。スパゲッティモンスターです。
私は主にゲーム制作で発生するエンジンの問題を解決する役割を担当しています。
キャラクターの色がマビノギと微妙に違います!ある日、アートチームからヘルプ要請がありました。
「マビノギのキャラクターシェーダーをUnreal Engineに移行したのですが、キャラクターの色が微妙に違います!」
「Unlit でテストしてみてもトーンが違います!」
どうにかしてプレイオネエンジンでの色に近づけることができたとしても、その場しのぎではなく、もっと根本的な解決が必要でした。
髪の染色にハマっているミレシアンの皆さんにとって、キャラクターの色が変わってしまうのは絶対にあってはならないことだからです!
<プレイオネエンジン vs Unreal Engine(Unlit) vs Unreal Engine(マビノギ専用シェーダー) の色の比較>
この記事では、エンジンが変更され、キャラクターの色が違って見える問題の原因を見つけ、解決するために悩んだ内容を共有したいと思います。
色とは何か?ゲームエンジンでシェーダー Unlit という話をする前に、私たちがよく話す色とは何なのか、少し見てみましょう。
色とは何でしょうか?
私たちの目は、光が物体に到達した後に反射される波長のうち、可視光線の波長を物体の色として認識しています。
リンゴが赤く見えるのは、リンゴが赤い光だけを反射し、他の光はすべて吸収するからです。
リンゴが反射した赤い光だけを見るのでしょうか?
そうではありません。自然界では、このようにリンゴの周りの物体や物質によって光が吸収、
反射され、その反射された光が別の物体に到達すると吸収/反射される過程が反射する光がなくなるまで繰り返されます。
もしすべての色が間接的にリンゴから反射して目に入るとしたら、私たちの目はどのように色を認識するのでしょうか?可視光線を検出するものでもあるのでしょうか?
はい、目には色を感知する錐体細胞と明暗を感知する桿体細胞があります。
ハッ…これはいきなり何の話ですか? むしろ、シェーダー Unlit の話をしろとどこからか聞こえてくるようです。
もう少し辛抱強くお待ちいただければ、私の全体像を把握してうなずくことでしょう。
実は細胞名なんてどうでもいいんです。
この細胞を通して色と明暗を感知し、脳神経に伝達することで、脳で色を認識するようになっています。
<画像出典: ウィキペディア>
お伝えしたいのはこの部分です。
錐体細胞と桿体細胞の分布が明るさや色によって異なるということです。
つまり、明るさや色を知覚する程度が一定ではないということです。 例えば、私たちは暗い場所や緑色を見たときに、より繊細に感じることができます。
これは、緑色の植物が多い自然環境では、それを見分ける能力や、暗闇にうまく適応することで生存に有利だったという話もあります。
とにかくこのような理由から TV, モニターのようなディスプレイ機器も人の目の認知能力に合わせて作られています。
可能であれば、ディスプレイの解像度もせっかくなら人間の目がよく感知する領域をより多く使用し、あまり感知しない領域を少なくするとよいです。
よく感知する領域の解像度が高ければ、画質が良いと感じるでしょう。
このようにすべての色と明暗が同じ分布で出力されるのではなく、より暗い部分の解像度を高めて出力されるようにつくられています。
ガンマカーブは、このように人間の目の認識能力に合わせてディスプレイの輝度レベルを調整する目的で使用されます。
![](https://static.nexon.co.jp/mabinogi/Notice_image/eternity/012/20240624165122376.jpg)
以下はCRTモニターで出力した場合、入力値より暗い領域が多く分布するように出力されることが確認できます。 (右側の画像)
![](https://static.nexon.co.jp/mabinogi/Notice_image/eternity/012/20240624165132892.jpg)
<画像出典: nVidia>
最近では HDR ディスプレイが登場し、より多様な明るさを表現する必要があるため、以前のガンマ方式の代わりに新しい信号計算方式を使用して画面に出力することもあります。
ただ、それまではディスプレイ装置は上記のように製作された場合が多かったため、色情報ではなく単純なデータ値で計算されていて、線形データを補正して使用していました。
ここまで「色とは何か」というテーマで見てきました。
私たちがモニターを通して知覚する色は、次のような要素が影響していることを確認しました。
・「リンゴが赤い光の波長を反射する」のように、光の反射/吸収/散乱特性を定義するネタ。
・リンゴに直接影響を与える光
・他の物体によって反射された後、リンゴに届き間接的に影響を与える光
・モニターで出力される結果と、これに対するガンマ補正またはトーン補正計算。
自然界ではさらに多くの要素が色に影響を与えていますが、プレイオネとUnreal Engine のキャラクターの色の違いを見るために考える要素は、上記の 4 つに要約することができます。
いかがでしょうか? 錐体細胞...言及しておくべきだったのかなぁと後悔しますね。
プレイオネと Unreal Engine の違い先ほど、色に影響を与える要因のうち4つを見てきましたが、2つのエンジンはこの4つに対して、それぞれどのような機能を提供しているのでしょうか。
光に対するマテリアルの反射/吸収などの特性は、ゲームエンジンでマテリアル (またはシェーダー)で定義します。
(ちなみに、光に対するマテリアルの影響が全くないものは、Unreal Engineでは Unlitと呼ばれ、この時は光に関係なく常に設定された色で表示されます。)
プレイオネからシェーダーをそのままUnreal Engineに移したということなので、これによる違いはないとしましょう。
では、残る要素は以下の通りです。
・直接的、間接的に影響を与える照明
・モニターで出力される結果と、これに対するガンマ補正またはトーン補正計算。
マビノギが 移植する Unreal Engineには、ルーメンという照明システムがあります。
リアルタイムでシーンに影響を与える照明の直接光、間接光を計算してくれます。
<ルーメン使用前後の結果比較>
![](https://static.nexon.co.jp/mabinogi/Notice_image/eternity/012/20240624175727216.png)
これは昔のプレイオネにはない機能で、この照明システムの違いが色味に影響しているのでしょう。
もう一つの違いとして、マビノギはガンマ補正を使用していますが、Unreal Engineは Tone mapperというシステムを使用しており、ガンマ補正や他の補正方法をサポートしています。
トーン補正の違いもやはり色に影響する要因なので、その違いを確認する必要があります。
Tone mapperによるトーン補正の違いとトラブルシューティング Unreal Engineはポストプロセスと呼ばれる機能で Tone mapperをサポートしていますが、私たちがカメラで使っているフィルター効果のようなものもこのような事後的計算機能だと言えます。
ポストプロセスでは、以下のようなカラーグレードテクスチャでガンマ補正の代わりにカラー補正を計算していました。
![](https://static.nexon.co.jp/mabinogi/Notice_image/eternity/012/20240624170213936.png)
エンジンのデフォルト値が色補正を無条件に使用するように設定されていました。
そこで、関連パラメータの値を調整して、カラー補正を使用せず、ガンマ補正のみを計算するように修正しました。
その結果、 Unlit シェーダーを使用した場合、キャラクターがプレイオネと同じ色で出力されることが確認できました。
<プレイオネ vs Unreal Engine(Unlit)vsUnreal Engine(マビノギ専用シェーダ)トーン補正後色比較>
![](https://static.nexon.co.jp/mabinogi/Notice_image/eternity/012/20240624170806824.png)
「さあ、まだ Unlit シェーダー基準ですが、キャラクターのトーンがプレイオネと同じになりました!カラー補正をしないようにパラメータ設定をすればOKです。」
しかし、これはアートチームが望んでいた結果ではありませんでした。
「FXと背景のほうは色補正を使いたいのですが、キャラクターだけトーン補正を例外にできないのでしょうか?」
背景はキャラクターのトーンを気にせずカラー補正を使用したいのですが、キャラクターのためにカラー補正を使用しないと、背景の色味が思うように出ないという問題が発生します。
<キャラクター基準でトーンを合わせると背景のトーンが変わる (左:背景にトーンを合わせた場合、右:キャラクターにトーンを合わせた場合)>
「トーン補正を計算する Tone mapper 段階でキャラクターかどうかだけ区別することができれば、キャラクターだけカラー補正をしないように例外処理してみることができますが、方法はないのでしょうか?」
悩んでいたところ不意にアイデアが浮かびました。キャラクターのアウトライン!
そうです。トーンシェーディングでは常にキャラクターの輪郭を描きます、
マビノギエタニティでは、エンジンのポストプロセス機能を使ってキャラクターの輪郭を描いています。
この機能をうまく応用して、キャラクターの輪郭を描くときにキャラクター識別マスク情報も記録して渡せば、
トーン補正や Bloomまでキャラクターだけ例外処理したいところにはすべて使ってみることができます。
<キャラクターの輪郭を 描くとき 別途記録したキャラクターマスク情報>
このキャラクター識別マスク情報でトーンマップ補正だけでなく、 Bloomも キャラクターだけ 別々に調整できるように機能を追加することができました。 (ほくほく)
<キャラクター専用トーンマップパラメータ制御>
<キャラクター専用 Bloom パラメータ制御>
照明計算の違いとトラブルシューティングここまで進めた結果、修正すると Unlit シェーディングモデルで作成したときは、プレイオネと同じ色味に見えることを確認しました。
<プレイオネ vs Unreal Engine(Unlit)vs Unreal Engine(マビノギ専用シェーダー)トーン補正後色比較>
しかし、右側のマビノギ専用シェーダーを使用しているキャラクターは、やはり色味が違って見えます。
ただ Unlitで使用できないのですか? このように考えることができます。
Unlit は、文字通り照明の影響を受けないシェーダーです。
したがって、影を落とす木の陰の下にキャラクターが入るかどうかに関わらず、常に上記のようなフェイクライトが見えます。
そのため、マビノギ専用のシェーダーをUnreal Engineに合わせて標準化する必要がありました。
マビノギ専用シェーダーも Unlitのようにプレイオネと同じ色で表現しつつ、光と影を同時に反映させることが今回の目標です。
まず、なぜこんなに暗く見えるのでしょうか?
<シャドウマップ比較>
実はマビノギ専用シェーダーを使用しているキャラクターは、常に影がかかるようにシェーダーが実装されており、暗く見えていました。
私は影がかからないように、影が必要なときだけ影がかかるように修正してみました。
影の領域でない場合は明るくなったものの、光が計算される領域の感じがトゥーン感より実写感がありますね。
おそらく、Unreal Engine にインポートする際に、このような理由で常にシャドウが描画された状態で作られているようです。
トゥーンシェーディングの感覚を維持するために、キャラクターの影の色を別々に記録し、
またトゥーンシェーディングで使用しないバッファはもったいないので、ライティングの色を記録する用途に変更し、
シェーディングの結果に反映してみました。
<修正前(ライティングカラーのみ存在)vs 修正後(影の色とライティングの色の分離後の陰影に応じてトゥーン方式で合成>
これで、シャドウ、基本照明の計算結果がプレイオネと同じように計算されることが保証されます。
次に、Unreal Engineが提供するルーメン間接光環境で、マビノギ専用シェーダーを使用した場合、間接光の計算結果が過大になり、
キャラクターの色が正しく出ないことを確認しました。
<キャラクターに対するルーメンの影響力が高い状態 vs 低い状態>
これは、マビノギ専用のキャラクターシェーダーを使用する場合、
ルーメンの影響力を個別に制御できる機能を提供することで解決しました。
<キャラクター専用ルーメンパラメータの制御>
このようにルーメンを使用する場合とそうでない場合、キャラクター専用のスカイライトの影響度パラメータ、
ポイントライトのキャラクターの影響度パラメータなどを提供し、 背景用のライティングとキャラクター用のライティングを
それぞれ別々に制御できるように機能を提供しました。
<キャラクター専用 ポイントライトの パラメーターを制御する>
これで、背景ライティングの設定とは別にキャラクター専用のライティングを設定できるようになり、
背景ライティングによってキャラクターの色味が大きく変化しないように制御できるようになりました。
最後に…
ここまで、プレイオネと Unreal Engine のキャラクターの色の違いを発生させる原因を特定し、解決していく過程を見てきました。
最初は単純にプレイオネと同じ色味を見せよう!と始めたのですが、やっているうちにもっと改善できる部分が見えてきて悩んでしまいます。
キャラクターをレンダリングするための基礎作業が終わっただけで、これからが本番です。
まだまだ道のりは遠いですが、より美しいグラフィックでミレシアンの皆さんにお見せする日を夢見て頑張ります!
ありがとうございます。
『Writer スパゲッティモンスター』