Radeon で Pixal3D(画像1枚から色付きの 3D を作るモデル)を試す技術検証の中で、C++ 版の trellis.cpp で作ったテクスチャの色が、入力の絵より暗く、濃く出ました。キャラクターのパーツを並べると、どれも一段沈んだ色になっています。書き出しの誤りを疑いたくなりますが、そこではありませんでした。
結論
- キャラのパーツ 7 本で、テクスチャはおよそ入力の 1.4〜2.0 乗でした(髪だけ 1.1 乗)。金属度は全部 0 なので、ベース色そのものが暗いということです。
- trellis.cpp の書き出しは公式(TRELLIS.2)と同じ ×255 で、変換の誤りではありません。
- チャンネルごとの曲線(テクスチャ = 入力^g)で直すと、少ない色の色相が崩れました。
- 入力のカメラで正面を光なしで描き、同じ画素の色の組から 32³ の色の表(3D LUT)を作って直しました。ずれは 0.059〜0.228 から 0.012〜0.061 に下がりました(色の表を作ったのと同じ正面の画素で測った値です)。
試した環境
- Pixal3D を trellis.cpp v0.8.1(HIP でビルド)で動かしたもの。Radeon RX 7900 XT(VRAM 20 GB)、Ubuntu、ROCm 7.2.4
- 1024・色付き・16 ステップ・画角 15°
- 入力: 1人のキャラクターのパーツ 7 本(素体・髪・上着・シャツ・ズボン・靴・リュック)
- 直す処理は、trellis-cli を呼ぶ自作の Python スクリプトの中にあります(numpy と Pillow だけ)
どれくらい暗いか
正面で入力と重ねて比べると、たとえばリュックの黄土色は焦げ茶に沈み、白に近いシャツは肌色寄りになっていました。明るい色はそれほど変わらず、中くらいの色ほど沈んで濃くなっています。
チャンネルごとの曲線で直すのをやめた
最初は、R・G・B のチャンネルごとに「テクスチャ = 入力^g」の曲線を当てはめ、その逆で直そうとしました。すると、少ししか無い色の色相が崩れました。目が緑に、シャツのボタンが青緑に、肩ひもがオリーブになったのです。チャンネルごとの曲線は、ずれ方が色ごとに違うと合わせきれません。そこでこの方法は捨てました。

3D LUT で直す
色ごとにずれを持てるよう、色の表(3D LUT)にしました。流れは次のとおりです。
- 入力のカメラで、形の正面を光なしで描きます。カメラは立たせた形の +Z の側、距離は 0.5/tan(fov/2)(trellis-cli がログに出す distance と同じ式)、画面は切り抜きの正方形です。描いた画素と入力の切り抜きの同じ画素から、(テクスチャの色, 入力の色)の組を集めます。
- 輪郭から 3 画素の範囲と、色の境目の近く(7×7 の範囲で色が動く所)は使いません。重なりのわずかなずれで、別の色と組になってしまうからです。
- 組から、ずれ(入力 − テクスチャ)の 32³ の表を作ります。格子ごとのずれは中央値です。空の格子には、近くの格子のずれを 1・0.6・0.3 の掛け目で3段まで染み出させます。それより遠い色(正面に無い色)は直しません。
- テクスチャの画素ごとに、表のずれを三線形補間で足します。
- 組が 5,000 に満たないときと、直してもずれの中央値が減らないときは、直しません。直せなくても、失敗にはしません。直したときだけ、元のテクスチャを別に残します。
この方法が成り立つのは、Pixal3D が画素に揃えて形を作るからです。外接箱で合わせなくても、正面の輪郭が切り抜きとよく重なります。7 本で IoU は 0.976〜0.987 でした。正射影にして外接箱で合わせた場合は 0.915〜0.973、画角 25〜49.13° の 5 本でも 0.965〜0.978 です。直す処理は 7 本で 1.6〜2.6 秒でした。
直した結果
ずれは、中央値の絶対差(0〜1)で測りました。
| パーツ | 直す前 | 直した後 |
|---|---|---|
| 素体 | 0.098 | 0.012 |
| 髪 | 0.059 | 0.034 |
| 上着 | 0.228 | 0.061 |
| シャツ | 0.094 | 0.019 |
| ズボン | 0.078 | 0.013 |
| 靴 | 0.114 | 0.019 |
| リュック | 0.153 | 0.038 |
これは、色の表を作ったのと同じ正面の画素で測った値です。背面は、Blender で描いて目で見ただけです。
この表とは別の回に、上着をもう1本作りました。組は 465,828 個で、ずれは 0.212 から 0.022 に下がり、直す処理は 1.7 秒でした。Blender で描くと入力の色に戻り、背面も同じ色でした。ただし、ボタンは暗いままでした。
光を当てて描くと、少し明るく見える
入力の絵には、描かれた光と影が入っています。その色に合わせるので、ビューアで光を当てて描くと、入力より少し明るく出ます。素体の肌が淡く見えたのはこのためです。
確かめていないこと
- 色が暗く濃く出る原因。公式の学習データの抜き出し(
dump_pbr.py)では、テクスチャの無い素材は Blender の線形の色を、テクスチャのある素材は sRGB の画素を、どちらも変換せずに入れています。この混ざりのせいではないかと考えていますが、確かめていません。 - 背面への効き(目で見ただけです)。
おわりに
Pixal3D の色の沈みは、チャンネルごとの曲線では直しきれませんでした。正面の画素の組から作った 3D LUT では、7 本とも正面のずれが下がりました(表を作ったのと同じ画素で測った値です)。ただし、正面に無い色は直さず、背面への効きは目で見ただけです。
※ Pixal3D と trellis.cpp の色の出方は、執筆時点の版(trellis.cpp v0.8.1)での振る舞いで、いまは変わっている可能性があります。


