mieki256's diary



2024/11/21(木) [n年前の日記]

#1 [blender] blenderでobjエクスポートした際の色について調べてた

blender 4.2.3 LTS で svg をインポートして、Wavefront (.obj) でエクスポートした際に、マテリアルカラー(.mtl) 内の値(Kd)が、svg のソレとは全然違う値になる件について調べてた。

以下のやり取りで気になる話が…。

_RGB values wrong when exporting as OBJ - Support / Materials and Textures - Blender Artists Community

ガンマ補正がどうとか言ってるように見える。

blender 4.2.3 ではなく、blender 2.79b なら違う結果になるのだろうかと気になって、blende 2.79b で試してみたけれど、やはり .mtl 内の値は svg のソレと全然違う値になっていた。ただ、blender上で各マテリアルのベースカラーを確認した際、「ガンマ補正済」と表示されている点が気になった。

また、シーン設定 → カラーマネジメント → 表示デバイス、が通常では「sRGB」になっているけれど、ここを「なし」にすると、全体的に色が黒くなることに気づいた。その状態で確認したベースカラー値は、.mtl に記述されている値とほぼ同じになっている気がする…。

つまり、以下の状態なのではないかと…。仮説だけど。

ソースを眺めてみた :

blender 2.79b のスクリプトを眺めてみた。

.obj のエクスポートは、以下の Pythonスクリプトが担当してるはず。
(blender 2.79bインストールフォルダ)\2.79\scripts\addons\io_scene_obj\export_obj.py

Kd (Diffuse color)の出力部分は以下だろうか。
fw('Kd %.6f %.6f %.6f\n' % (mat.diffuse_intensity * mat.diffuse_color)[:])  # Diffuse

おそらく、blender が持ってるマテリアル情報をそのまま出力しているように思える。


svg をインポートする処理を眺めてみた。以下のファイルが関係してそう。
(blender 2.79bインストールフォルダ)\2.79\scripts\addons\io_curve_svg\import_svg.py

関連する部分は以下だろうか。
def SVGGetMaterial(color, context):
    """
    Get material for specified color
    """

    materials = context['materials']
    rgb_re = re.compile('^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,(\d+)\s*\)\s*$')

    if color in materials:
        return materials[color]

    diff = None
    if color.startswith('#'):
        color = color[1:]

        if len(color) == 3:
            color = color[0] * 2 + color[1] * 2 + color[2] * 2

        diff = (int(color[0:2], 16), int(color[2:4], 16), int(color[4:6], 16))
    elif color in svg_colors.SVGColors:
        diff = svg_colors.SVGColors[color]
    elif rgb_re.match(color):
        c = rgb_re.findall(color)[0]
        diff = (float(c[0]), float(c[1]), float(c[2]))
    else:
        return None

    diffuse_color = ([x / 255.0 for x in diff])

    if context['do_colormanage']:
        diffuse_color[0] = srgb_to_linearrgb(diffuse_color[0])
        diffuse_color[1] = srgb_to_linearrgb(diffuse_color[1])
        diffuse_color[2] = srgb_to_linearrgb(diffuse_color[2])

    mat = bpy.data.materials.new(name='SVGMat')
    mat.diffuse_color = diffuse_color
    mat.diffuse_intensity = 1.0

    materials[color] = mat

    return mat

svg内で記述されていたRGB値は、diffuse_color に 0.0 - 1.0 の範囲で入るけど…。関数 srgb_to_linearrgb() を通した値を最終的なRGB値として処理している。

srgb_to_linearrgb() も同じファイル内で記述されていた。内容は以下。
def srgb_to_linearrgb(c):
    if c < 0.04045:
        return 0.0 if c < 0.0 else c * (1.0 / 12.92);
    else:
        return pow((c + 0.055) * (1.0 / 1.055), 2.4);

svgファイル内に記述されていたRGB値を、この関数を通して確認してみたところ、.mtl に記述された値とほぼ同じになった。つまり…。
  • blenderでsvgをインポートする際に、svg内のRGB値は、srgb_to_linearrgb() で変換されてから読み込まれてる。
  • blender内部ではガンマ補正されてないRGB値を持ってるけれど、UI上では補正されたRGB値が表示されてる。
  • Wavefront (.obj)形式でエクスポートすると、blende内部で持ってたガンマ補正されてないRGB値が、.mtl内にそのまま出力される。

ということは、この関数と逆の計算をする関数を作って、.mtl 内の値を計算してやれば…。

以上です。

過去ログ表示

Prev - 2024/11 -
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project