2024/11/22(金) [n年前の日記]
#1 [blender] blenderでobjエクスポートした際の色について調べてた。その2
_昨日
に引き続き、blender 4.2.3 LTS で svg をインポートして Wavefront (.obj) でエクスポートした際に、マテリアルカラー(.mtl) 内の値(Kd、Diffuse color)が svg のソレとは全然違う値になる/全体的に色が暗くなる件について調べてた。
svg をインポートした際に、scripts\addons\io_curve_svg\import_svg.py 内で、srgb_to_linearrgb() を経由してRGB値が変換されることは分かった。ということは、逆の計算をする関数を作れば、.mtl内のRGB値を、元々のsvgのRGB値に戻すことができるのではないかと。
関数の名前からして、逆の計算をする関数が ―― linearrgb_to_srgb() が既に書かれてそうだなと…。ググってみたら見つかった。
_color management - What's the exact gamma correction Blender uses? - Blender Stack Exchange
_blender/source/blender/blenlib/intern/math_color.c at master - dfelinto/blender
_#94202 - crash or error when using GPUFrameBuffer.read_color(... data=data) - blender - Blender Projects
_FBX SDK Python2020 の使用例2(マテリアル書き込み編 ブレンダーからクリップスタジオモデラーマテリアル画面へ)|ハイドロキャリス
C言語で書かれている事例は以下。
Pythonで書くなら以下になるのだろうか。
svg をインポートした際に、scripts\addons\io_curve_svg\import_svg.py 内で、srgb_to_linearrgb() を経由してRGB値が変換されることは分かった。ということは、逆の計算をする関数を作れば、.mtl内のRGB値を、元々のsvgのRGB値に戻すことができるのではないかと。
関数の名前からして、逆の計算をする関数が ―― linearrgb_to_srgb() が既に書かれてそうだなと…。ググってみたら見つかった。
_color management - What's the exact gamma correction Blender uses? - Blender Stack Exchange
_blender/source/blender/blenlib/intern/math_color.c at master - dfelinto/blender
_#94202 - crash or error when using GPUFrameBuffer.read_color(... data=data) - blender - Blender Projects
_FBX SDK Python2020 の使用例2(マテリアル書き込み編 ブレンダーからクリップスタジオモデラーマテリアル画面へ)|ハイドロキャリス
C言語で書かれている事例は以下。
float linearrgb_to_srgb(float c) { if (c < 0.0031308f) { return (c < 0.0f) ? 0.0f : c * 12.92f; } return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f; }
Pythonで書くなら以下になるのだろうか。
def linearrgb_to_srgb(c): if c < 0.0031308: if c < 0.0: return 0.0 return c * 12.92 return (1.055 * pow(c, (1.0 / 2.4)) - 0.055)
◎ 検証 :
手持ちのsvgファイル内では「#242424」と書かれていたRGB値が、blenderからエクスポートした .mtl内では以下の値になっていた。
PythonのIDLE上で計算してみる。
linearrgb_to_srgb() を定義して試してみた。
0x24になった。合ってる気がする。
他の値も入れて確認してみたけれど、一部の値で誤差が出るのか全てがピッタリにはならなかったものの、ほとんど大体は合ってる値になった。
ということで、blender からエクスポートした Wavefront (.obj) の色が全体的に暗い場合は、この関数を通してRGB値を求め直してやれば本来のRGB値に近づいてくれる可能性が高い。
ただ、blender に .obj をインポートする際は、RGB値を変更しちゃうと二重に変換がかかってしまってマズイことになりそう。
newmtl Black01 Ns 96.078431 Ka 1.000000 1.000000 1.000000 Kd 0.017642 0.017642 0.017642 Ks 0.500000 0.500000 0.500000 Ke 0.000000 0.000000 0.000000 Ni 1.000000 d 1.000000 illum 0
PythonのIDLE上で計算してみる。
>>> hex(int(0.017642 * 255.0)) '0x4'0x24 になってほしいのに、0x04 になってる。全然違う。
linearrgb_to_srgb() を定義して試してみた。
>>> def linearrgb_to_srgb(c): ... if c < 0.0031308: ... if c < 0.0: ... return 0.0 ... return c * 12.92 ... return (1.055 * pow(c, (1.0 / 2.4)) - 0.055) ... >>> hex(int(linearrgb_to_srgb(0.017642) * 255.0)) '0x24'
0x24になった。合ってる気がする。
他の値も入れて確認してみたけれど、一部の値で誤差が出るのか全てがピッタリにはならなかったものの、ほとんど大体は合ってる値になった。
ということで、blender からエクスポートした Wavefront (.obj) の色が全体的に暗い場合は、この関数を通してRGB値を求め直してやれば本来のRGB値に近づいてくれる可能性が高い。
ただ、blender に .obj をインポートする際は、RGB値を変更しちゃうと二重に変換がかかってしまってマズイことになりそう。
◎ 実際に表示してみた :
しばらく前に、Wavefront形式(.obj .mtl)を読み込んで、C言語のヘッダファイルの形に変換するPythonスクリプトを書いたのだけど。
_mieki256's diary - OpenGLでモデルデータを読み込めそうか調べてる。その6
そのスクリプトに、前述の関数を追加して、.mtl内の Kd にガンマ補正をかけたRGB値を出力するように修正して、見た目がどう変わるか確認してみた。
せっかくだから github にアップロードしておいた。pyobj2c.py が、obj → c に変換するPythonスクリプト。
_mieki256/pyobj2c
OpenGLで描画するサンプルソース 01_drawobj.c をコンパイルして動かしてみた。スクリーンショットを以下の順番で並べてある。
ガンマ補正をかけたほうが、全体的に色が明るくなって、blender上での見た目に近い色になっていることが分かる。まあ、照明の当て方次第で色は変わってしまうものだけど…。それでも、今までの .obj .mtl より全然マシな見た目になってくれたかなと…。
_mieki256's diary - OpenGLでモデルデータを読み込めそうか調べてる。その6
そのスクリプトに、前述の関数を追加して、.mtl内の Kd にガンマ補正をかけたRGB値を出力するように修正して、見た目がどう変わるか確認してみた。
せっかくだから github にアップロードしておいた。pyobj2c.py が、obj → c に変換するPythonスクリプト。
_mieki256/pyobj2c
OpenGLで描画するサンプルソース 01_drawobj.c をコンパイルして動かしてみた。スクリーンショットを以下の順番で並べてある。
- blender 4.2.3 LTSのマテリアルプレビュー
- pyobj2c.pyでガンマ補正した描画結果
- ガンマ補正無しの描画結果
ガンマ補正をかけたほうが、全体的に色が明るくなって、blender上での見た目に近い色になっていることが分かる。まあ、照明の当て方次第で色は変わってしまうものだけど…。それでも、今までの .obj .mtl より全然マシな見た目になってくれたかなと…。
[ ツッコむ ]
以上です。