【UE5】トーンマッパ(Tonemapper)を改造してUnityと同じ色出力にしてみた - Unreal Engine 5.3

作業環境

始まり

Unreal EngineとUnityの両方を触ったことある方なら経験済みと思いますが、Unlitシェーダーを使用しているにも関わらず、最終的な見た目に差分が発生します。

左がUnreal Engine、右がUnity

ゲームエンジンが違うので差分が発生するのは当然です。

――当然なのですが、シェーダーを共通化したい時って稀にあるじゃないですか。

今回は技術検証目的で共通化が必要になりました。

という訳で、エンジン改造で差分を握り潰していきます。

差分の原因を探す

差分を見つけていきましょうか。

テクスチャを比較する

インポートしたテクスチャ形式に隠れた差分が無いか確認して見ます。

テクスチャ形式 画像
Unreal Engine BC1_TYPELESS sRGB
Unity BC1_SRGB

sRGBにチェックを入れた際の挙動に差分は無さそうですね。
テクスチャが上下反転して見えるのは、UV座標のVの仕様差分ですね。
これは特に問題ないです。

BasePassを比較する

UnlitシェーダーでSceneColorに書き込んでいる部分を比較して見ます。

Scene Color Format 画像
Unreal Engine R16G16B16A16_FLOAT
Unity R11G11B10_FLOAT

SceneColorのテクスチャ形式に差分があるので、書き込み結果が微妙に異なりますね。
ただ、この誤差が原因で冒頭の画像のような乖離が起きるとも考えにくいので、一旦は保留にしておきましょう。

R成分 G成分 B成分
UE 0.92969 0.19434 0.19824
Unity 0.92969 0.19336 0.19531

Tonemapperを比較する

トーンマッパを適用しているトーンマップパスを比較して見ます。

左がUnreal Engine、右がUnity

はい、まぁ、順当にここが差分の原因ですよね。

原因の纏め

原因が2つほど見つかりました。
1つはTonemapの違い、もう1つはSceneColorのテクスチャ形式による誤差です。

後者はビットによる誤差なので、見逃しても問題ない範囲だと思いますが・・・
Tonemapの違いは許容範囲外でしょう。

パラメータ調整で解決できぬか?

別の記事でも少し触れたExpand GamutTone Curve Amountで解決できないか。

結論から言うと無理です。

細かいことは諸々と省きますが、Unity URPのTonemapper Mode Noneは、LinearからsRGB変換のみ適用されています。
厳密にはColorLUTも適用していますが、初期設定では先ほどのビットの誤差と同程度の差分しか発生しないです。

左がLUT適用前、右がLUT適用後

トーンマップを改造していく

パラメータ調整で解決できない場合の選択肢は限られてきます。
※たぶんできないと思うけど、改造しちゃえ!という結論ありきだから、正直そこまで調べていないですわ

  1. トーンマップを打ち消すような計算を入れる
  2. エンジン改造してトーンマップ計算を合わせる

1のやり方は古から伝承されているので、皆さんご存じでしょうから、新ネタとしてエンジン改造の方法をご紹介します。

――本当のこと言うと、打ち消し計算って面倒・・・
せや、エンジン改造で手抜きしよーって感じ。

リポジトリ

最新バージョンのみ保守しています。
過去バージョンが動かないと言われても基本的には知らんがなスタイルです。

実装

実装というか改修部分の軽い説明です。

Engine/Source/Runtime/Engine/Classes/Engine/Scene.h

ポストプロセスボリュームの設定に有効性を制御するパラメータを追加しています。

今回はTonemapping Mode Noneだけを実装するので、チェックボックスによるオン/オフ切り替えです。

時間が取れたらNeutralも実装してみたいので、そのタイミングでenumにしようかなと考えています。

githubで実装を見る(L1178-L1179)
githubで実装を見る(L2238-L2240)

Engine/Source/Runtime/Engine/Private/Scene.cpp

初期値(無効)をセットしています。

githubで実装を見る(L652)

Engine/Source/Runtime/Engine/Private/SceneView.cpp

ポストプロセス設定のオーバーライド処理です。
線形補間するようなパラメータではないのでLERP_PPではなくSET_PPです。

どこでオーバーライドされるのかというと、レベルに配置したポストプロセスボリュームに含まれるポストプロセス設定 ↔ カメラに含まれるポストプロセス設定がよくあるやつですね。

UEに慣れていないと勝手にパラメータが変わっている風に見えるので、この辺りはもう少し案内を整備して欲しいですね。普通に分かりにくいし、不具合の要因になっているから困る。

githubで実装を見る(L1764)

Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessTonemap.cpp

UnityURP Tonemapping Mode Noneを使用するか否かの判断材料として、USE_UNITYディレクティブを定義しています。

githubで実装を見る(L92)


先ほどのポストプロセスボリューム設定のパラメータに従ってバリエーションの有効性を制御しています。

githubで実装を見る(L103)
githubで実装を見る(L161)

Engine/Shaders/Private/PostProcessTonemap.usf

UnityURPではテクスチャ形式でsRGBを指定しているため、シェーダー側でLinear to sRGB変換をしていません。
Unreal EngineはUNORMなので、シェーダー側でLinear to sRGB変換をする必要があります。
そのための関数ですね。

githubで実装を見る(L184-L192)


UEのColorLUTは結構影響が強いので除外しておきます。

githubで実装を見る(L501-L506)


Linear to sRGB変換をしています。

githubで実装を見る(L548-L549)
githubで実装を見る(L589-L592)

完成!!!

幾つかパラメータ設定をします。

ブルームをオフ
自動露出をオフ
ビネットをオフ
本改造のトーンマッピングを有効化
左がUnreal Engine、右がUnity

じゃじゃ~ん。

Unlitシェーダーで作成した際の見た目が同じになりましたね。

ペイントソフトのレイヤー差分で見ると1~2前後の差分が発生しますが、これは先ほど触れたSceneColorのテクスチャ形式によるものなので、見逃してくださいな。

BasePassの誤差を潰す (R11G11B10_FLOAT vs R16G16B16A16_FLOAT)

前述の通り、BasePassのSceneColorのテクスチャ形式がUnityとUnreal Engineでは異なるため、そのビットによる誤差が発生しています。

計算負荷は掛かりますが、実は、結構簡単にコレ、潰せます。

Unreal Engineのシェーダーファイルに汎用関数が沢山用意されています。
勿論、その中には、エンコードとデコード、パックとアンパックの関数もあります。

要はfloat3 <-> u32 as f11.f11.f10の変換関数があるので、これを組み込むことで書き込みする前にFP32精度からR11G11B10精度に劣化させることができるのです。

こんな感じにEmissiveピンに接続する直前にCustomノードで処理すれば完成です。


return UnpackR11G11B10F(PackR11G11B10F(Color));


RenderDocで比べて見るとCustomノードを挟んで出力した場合には、BasePassの書き込み結果がUnityと完全一致していると思います。

画像
Unreal Engine
Unity
Unreal Engine (ビット誤差潰し)


若干悲しいことを言うと仮にBasePassで合わせたとて、Tonemap適用後の書き込み先のテクスチャ形式が異なるので、最終的にはビットの誤差は絶対に発生します。

んで、書き込み先で握り潰しても、今度はそのテクスチャをGUI書き込みする場合は別シェーダーを使うので、これまた差分・・・と、まぁ、イタチごっこなのですわ。

ここまで極度に気にするのは拘りを通り越してウザいと思いますので、こういうやり方もあるよ程度に収めてもらえるとハッピーだと思います。

気にし過ぎも精神衛生上よくないよ。

おわり!!!

きっかけは技術検証のための見た目の互換性確保でしたが、UnityからUnreal Engineに作品移植とかでも応用できそうですね。

試しにセルルックの子たちを配置してみた。

左がTonemapping(ACES)、右が本改造のTonemapping(None)

やっぱりセル調の場合は色が素直に出てくれた方が調整しやすいですね。
背景の天球はTonemapping(ACES)で調整した色なので、ちょっと違和感ありますが、調整していないのが悪いだけ。

これを踏まえるとUnityはいいですね。

もちろん、Unreal Engineもセル調の表現さえ頑張ってしまえば、リアル調とセル調のハイブリットな結構つよつよ表現できるんですけどね。

普通に実装が大変です。(そりゃそう)


途中でも書きましたが、時間が取れたらTonemapping Mode Neutralも実装してみたいので、またいつか書くことでしょう。

その前にSMAAの記事を更新しないとなんだけどね。

色々とやりたいことが多すぎるんじゃ。

雑談

本当は1週間毎に記事を更新したいんだけど、やることを積み過ぎるとのんびりブログも書いてられないのよね。

ということで今回は結構溜まったので長いぞ。

ここから先は年齢制限のかかっている作品を取り扱うページとなります。


表示する

さぁ、本題の雑談です。
※技術的な内容は特典程度です。


基本的に扱う内容が叡智な作品についてのアレコレ。

技術と叡智を隔離しようかな、と考えていた頃もありました。

がしかし。

ツラツラと技術的なことについて綴っていくのって、いくら自身のアウトプットのためとはいえ、マジで怠い。

あーでも、今回の内容は結構書くの楽しかった。普通に勉強になったし。
ただし、SMAA、あなたは5.2の時に隅々まで見たからもう興味があんまりないのじゃ。

筆者さんは欲に忠実な人間さんです。

目の前に餌を吊るされれば当然頑張ります。

そう、その餌こそが、叡智な作品についてアレコレ綴れる場所。
SNSはやっていないことを前提とした話です。


ここまで大変よく頑張ってアウトプットできました。

自分、とってもえらいです。

ご褒美に存分と綴ってください。


セレオブ 店舗特典 画像更新編

セレオブの店舗特典画像、ようやく更新(2024.05.30)されましたね。

発売日7末ですよね。

普通に遅い。

トウリさんが可愛くなかったら許せなかった。

でも可愛かったからヨシッとします。


天使騒々 抱き枕カバー コンプリート編

いえーい。

みてみてー。

毎月購入した成果です。えっへん。

実質サブスク。

問題点としては、抱き枕本体を持っていないこと。

そして現状は購入予定もない。

もう少し広いお部屋にお引越し出来たら購入を考えるの。

百里(おざと)先生とオエリさん、めっちゃ刺さる。ぱねぇっす。好き。


オトメき 店舗特典編

見返したらFANZA GAMES高いだけど。

文句じゃないですよ。
他店舗と相対評価をすると特典数の割には高くないか?という事実を述べているだけ。

ORTHROSというブランドを知らなかった筆者が悪いんだけどね。
いつも通りFANZA GAMESで眺めていたら、出会ってしまって、流れでなんかポチッてた。

んで、割高でポチる分にはまだいいのよ。

筆者さんここでやらかしました。

『抱き枕』という文言だけで、それをパケ版と勘違いしたんですね。

えぇ。普通にダウンロード版でしたわ。

そりゃそうよ。

だっていつも見てるの通販の方じゃなくて、GAMESだもん。

あぁ。。。あほです。


というわけで、ソフマップさんにもお世話になりました。

過去作はダウンロード版でいいんだけど、新規はパッケージ版がいいという拘りを捨てきれなかった。

そして何故かソフマップで永遠とクレカが弾かれた。

最終的に不正利用疑われて停止されたわ。

解除してようやく使えるようになりました。

いくら年齢制限のコンテンツだからって、不正利用を疑わなくていいじゃない。

叡智なだけで不正じゃないのよ。


オトメき 体験版 読み上げツール編

モデルの検出精度は良好通り越して安定の100%です。

ツール画面
文字領域検出
文字切り抜き

約60,000文字、体験版なのに結構なボリュームだと思った。

結構なボリュームとは綴ったものの、筆者さん叡智な作品の体験版を遊んだの初めてなんだよね。

今まで絵を見てフィーリングで買ってたから何気に初めてだった。


OCR精度が高過ぎて『量子コンビューター』という誤字を発見する始末。
多分誤字だよね?


『諸手』
両手のタイプミスかと思いましたが、両手の意味もあるんですね。
シナリオライターさんって日本語の色々な表現を扱えていて博識ですよね。


OCR精度は完璧といって差し支えないのだけど、ツール自体の設計が甘かった。

  1. 人物名のトランジションで差分発生
  2. 完全に表示されていない状態なのにOCRタスクに突っ込む
  3. 検出事故が発生

解消するために、直近(履歴)の動きが落ち着いたらOCRタスクに突っ込むようにしたら、背景アニメーション時に不都合が出るようになったり、閾値を設けてアニメーション対応したら、今度は背景次第ではトランジションだけで閾値超過して突っ込まれてたりと、色々と経験できました。

なんでこの部分対応していないかって、当初の想定では、2000年頃の作品を動作対象としていたの。

その頃って当然ブランドにもよるけどアンチエイリアスすらままならない作品もあったじゃない。

そんな作品を中心に動作確認及び設計していたから、完全に要件から見逃していたの。

最終的にはトランジションを検出する領域を別途設定するように改修して、互換性を維持しつつ解消してあげました。

自作のツールってこの辺りを自由に解決できるから楽しいよね。

特に最近の作品は『読み上げ』が標準搭載されているから、自己満足以外でツールを作る理由なんてないんだよね。

まぁでもね。好きなことを技術的に必要なことと絡められると、趣味で満たされつつ技術力が勝手に付属してくるので、結構おすすめの方法です。


オトメき 体験版 感想編

姫乃さんと見かけると葛木さん家の娘さんと思ってしまいますね。

D.C.シリーズ、長寿ですよねぇ。

歴史が凄い。携わっている方々の努力なのでしょうね。かっこいい。

ちなみに筆者の好きな単語・台詞トップいくつかに『霧の都 ロンドン』があります。

D.C.がきっかけ。



白鈴女子とは世界線が異なることは理解しています。

――ただ、やっぱりなかのひとは同じ。

お声がおんなじなのですよぉ~。

特にね、悶絶している時の言葉にならない声。

もー、湊くんじゃん。

はぁ。。。

癒し。

筆者さん年齢的に湊くんはリアタイ世代じゃないのです。

だから地味に悔しかったの。

そんな想いを上書きしているのかと錯覚するような感じ。

いい意味で、やばいです。

ちょっと怒った気持ちが入った時の声が完全に湊くんです。

フォルマントのどの部分が似ているのか、時間を作れたら調べてみたいですね。

叡智なことに技術力を使う。

これこそエンジニアの鑑ですよ。
※嘘です。ごめんなさい。真面目に仕事している人が鑑です。



オープニングを流し終えてから店舗特典を映すのはズルいと思います。
否、宣伝方法としてとっても賢いと思いました。

こりゃ深夜にプレイしたら衝動買いしちゃうひとも居るでしょ。

筆者さんは体験版を遊ぶ前に衝動買いしちゃったけど。



――ディストピア

若干モヤっとしますね。

現実世界がこんなんだから創作世界ぐらい皆んな幸せに暮らして欲しい派の筆者さん。

体験版の範囲では精神崩壊するほどの暗暗シナリオがなかったですが、先に進むとどうなることやら。

ちょっとだけ不安です。


セレオブ 体験版 公開編

セレオブの体験版がようやく公開(2024/06/13)されましたね。

――おそい。

まって、やばい。

超解像度組み込まれてるwww

いらねぇだろwww

いれたかったんやろなぁ。気持ちはめちゃ分かるわ。新機能って実装楽しいもんね。

超解像度を実験的に組み込んでいる癖に、音声読み上げはないのですか。

筆者さんの読み上げツールも超解像度導入しようか検討中なの。

D.C.Ⅲ Rのフォントサイズが小さすぎて32x32にアップサンプリングした時、ちょっとボケるのよね。

セグメンテーションで解消すりゃいいんだろうけど、ちょっと試したい気持ちが強い。

本題とズレた。

セレオブの体験版が公開された現実を認知したのが2024/6/15 (土)

感想をぶち込みたくて急いで記事書いたよね。

今週と来週は遊ぶ時間作れなさそうだから、7月に入ってからかな。


おわり!!!

ふふ。

7月はセレオブ、8月はオトメき。

お仕事を頑張る理由付けにちょうどいいですね。

ぶっちゃけお仕事の内容もプログラムで好きなことなので、これ以上の理由なんて要らないですけど。

沢山あって困ることでもないですからね。


オトメきのオープニング映像、部分的にUnreal Engineで再現してみたい欲がヤバいのです。

学生時代はAviutlとBlenderしか扱えなかったのでランプのOPばっかり図形で再現していたんですけど、今の筆者さんはレンダリング全般を最低限扱う能力を手にしてしまいましたからね。


技術力を維持する代償としてプライベートの時間が圧倒的に減ってしまって、私欲を満たす事を蔑ろにしつつあるのですが。

それを解消するきっかけのひとつにゲームプレイの再開が含まれるので、どこかのタイミングで手を出してみたいですね。

てかさ、D.C.の世界を飛び回りたい。
地理データからテレイン作って、桜を量産したら行けそうな気もしたり、しなかったり。
D.C.のルックは結構再現可能なトゥーン・セル調なので、技術力の誇示にもちょうどいいと思うのです。

今年も残すところあと半年。

Unreal Engine関連で溜まった負債を急いで返済して可能な限り趣味に没頭する時間を作らねば。

頑張るぞー。