頂点の色のグラデーションは線形ではありません

Aug 21 2020

頂点彩色でデフォルトの立方体をペイントしています。下の4つの頂点を(0.25、0.25、0.25)としてペイントし、上の4つの頂点を(0.75、0.75、0.75)としてペイントします。

VERTEX PAINTモード(ホットキーSを使用して色を取得)で結果を調べると、立方体の下部は実際に(0.25、0.25、0.25)であり、上部は(0.75、0.75、0.75)です。

ただし、立方体の中点は(0.5、0.5、0.5)ではなく、〜(0.56、0.56、0.56)です。どういうわけか、勾配は線形ではありません。sRGBとLinearの問題はないと思います。そうしないと、下限と上限の値も間違っているためですが、それはその間の値にすぎません。では、ここでの問題は何ですか?本当に線形グラデーションが必要です。

編集。関連する問題:https://developer.blender.org/T71835 これは、頂点の色がどのように格納されるかと関係があることを示しています(明らかに8ビットのsRGB)。

この問題を再現するためのコード:

"""Script that checks vertex color interpolation error on the default cube.

run command: `blender --python gradient_error.py` (opens blender)
"""

import bpy

# Set up scene
sce = bpy.context.scene

# Select cube
scene = bpy.context.scene
for ob in scene.objects:
    ob.select_set(False)
    if ob.name == 'Cube':
        ob.select_set(True)
obj = bpy.context.view_layer.objects.active

# Get cube data
mesh = obj.data
vert_list = mesh.vertices

# Get the color map
if mesh.vertex_colors:
    color_map = mesh.vertex_colors.active
else:
    color_map = mesh.vertex_colors.new()

# apply colors
i = 0
for poly in mesh.polygons:
    for idx in poly.loop_indices: #vertices
        loop = mesh.loops[idx]
        v = vert_list[loop.vertex_index]
    
        z_coord = v.co.z

        # Paint bottom 4 vertices 0.25, top 4 vertices 0.75.
        if z_coord < 0:
            color_map.data[i].color = (0.25, 0.25, 0.25, 0)
        else:
            color_map.data[i].color = (0.75, 0.75, 0.75, 0)
        i += 1

# Give it this new material
mat = bpy.data.materials.new('vcolor_material')

# Deactivate shadows
mat.shadow_method = 'NONE'

# Apply material
mesh.materials.append(mat)

# Set Flat lighting and show Vertex Coloring
my_areas = bpy.context.workspace.screens[0].areas
my_shading = 'WIREFRAME'
for area in my_areas:
    for space in area.spaces:
        if space.type == 'VIEW_3D':
            space.shading.light = "FLAT"
            space.shading.color_type = "VERTEX"

bpy.ops.object.mode_set(mode='VERTEX_PAINT')

print("\nRan succesfully.\n")

回答

5 RichSedman Aug 25 2020 at 16:03

勾配は線形ですが、期待する色空間ではありません-次のように証明されています:

ここで、属性ノードは頂点カラー(Col)をシェーダーで使用できるようにしています。これは個別のRGBコンポーネントに分割され、生成された「X」座標(キューブの左側の0.0から右側の1.0まで実行されます)と比較されます。

勾配は線形ですが、終点は期待どおりではありません(つまり、青い垂直グリッド線はX = 0.5にあり、勾配線は下部の約0.05から上部の約0.525まで伸びています)。これは、sRGB色空間変換によるものです。

0.25と0.75の値は、sRGBから「真の」明るさに変換したときの約0.05と0.525の「絶対」値に関連しています-sRGB色空間は、明るさの0ビット整数表現を最大限に活用して作成することを目的としています可能な限り視覚的に多様であるため、範囲の開始/終了時の値と、人間の目に画面に表示されたときに目立つものに合わせて圧縮/拡張されます。

見る https://en.wikipedia.org/wiki/SRGB 次のグラフの赤い線に注意してください。

グラフの下部と右側にある軸の値を使用すると、x軸の0.75が「強度」で約0.5に変換されることがわかります-Pythonコードは0.75のsRGB値を適用し、約0.525の「強度」を生成しています上限について。同様に、下の0.25は、グラフの下端ではるかに小さい「強度」値に変換されています。その「強度」は、元のsRGB値ではなく、結果の頂点カラーグラデーションを生成するために線形補間されているものです。

1 uvnoob Aug 25 2020 at 13:32

シェーダーノードで使用するグレースケールデータのみが必要な場合は、これが醜い回避策です。代わりにアルファチャネルを使用してください。スクリプトでは、アルファ値をそれぞれ0.25と0.75に設定し、greater than 0.5ノードを使用して、アルファチャネルが線形に補間されていることを視覚的に確認しました。

おそらく、UVなどの他の属性も使用できます。

コノニカルな説明は私を超えているのではないかと思いますが、ここに問題を議論するスレッドがあります。回避策は、リンクされた回答に基づいています

https://github.com/KhronosGroup/glTF-Blender-IO/issues/542#issuecomment-569361267