Der Scheitelpunkt-Farbverlauf ist nicht linear
Ich male den Standardwürfel durch Scheitelpunktfärbung. Ich male die unteren vier Eckpunkte als (0,25, 0,25, 0,25) und die oberen vier Eckpunkte als (0,75, 0,75, 0,75).
Wenn ich das Ergebnis im VERTEX PAINT-Modus überprüfe (mit dem Hotkey S , um die Farbe zu erhalten), ist die Unterseite des Würfels tatsächlich (0,25, 0,25, 0,25) und die Oberseite (0,75, 0,75, 0,75).
Der Mittelpunkt des Würfels ist jedoch nicht (0,5, 0,5, 0,5), sondern ~ (0,56, 0,56, 0,56). Irgendwie ist der Gradient nicht linear. Ich denke nicht, dass es ein Problem mit sRGB vs Linear ist, da sonst die unteren und oberen Werte ebenfalls falsch wären, aber es sind nur die Werte dazwischen. Worum geht es hier? Ich brauche wirklich einen linearen Farbverlauf.
BEARBEITEN. verwandtes Problem:https://developer.blender.org/T71835 Dies besagt, dass dies etwas damit zu tun hat, wie die Scheitelpunktfarben gespeichert werden (anscheinend 8-Bit-sRGB).
Code zur Reproduktion dieses Problems:
"""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")
Antworten
Der Farbverlauf ist linear, jedoch nicht in dem von Ihnen erwarteten Farbraum - wie aus folgenden Angaben hervorgeht:
Hier stellt der Attributknoten dem Shader die Scheitelpunktfarbe (Col) zur Verfügung. Dies wird in separate RGB-Komponenten aufgeteilt und mit der generierten X-Koordinate verglichen (die von 0,0 links bis 1,0 rechts vom Würfel reicht).
Der Gradient ist linear, aber die Endpunkte sind nicht wie erwartet (dh die blaue vertikale Gitterlinie liegt bei X = 0,5 und die Gradientenlinie verläuft von etwa 0,05 unten bis etwa 0,525 oben). Dies ist auf die sRGB-Farbraumkonvertierung zurückzuführen.
Ihre Werte von 0,25 und 0,75 beziehen sich auf die "absoluten" Werte von ca. 0,05 und 0,525, wenn sie von sRGB in die "wahre" Helligkeit konvertiert werden. Der sRGB-Farbraum soll eine 0-Bit-Ganzzahldarstellung der zu machenden Helligkeit optimal nutzen es ist so visuell vielfältig wie möglich - also Werte am Anfang / Ende des Bereichs und komprimiert / erweitert, um dem zu entsprechen, was auf einem Bildschirm für das menschliche Auge erkennbar wäre.
Sehen https://en.wikipedia.org/wiki/SRGB und beachten Sie die rote Linie in der folgenden Grafik:
Anhand der Achsenwerte unten und rechts im Diagramm können Sie sehen, dass 0,75 auf der x-Achse in 'Intensität' in ungefähr 0,5 konvertiert wird. Ihr Python-Code wendet den sRGB-Wert von 0,75 an und erzeugt eine 'Intensität' von ungefähr 0,525 für die Obergrenze. In ähnlicher Weise wird der untere Wert von 0,25 am unteren Ende des Diagramms in einen viel kleineren Intensitätswert umgewandelt. Diese 'Intensität' wird linear interpoliert, um Ihren resultierenden Scheitelpunkt-Farbverlauf zu erzeugen - nicht Ihre ursprünglichen sRGB-Werte.
Wenn Sie nur Graustufendaten für die Verwendung in Shader-Knoten benötigen, finden Sie hier eine hässliche Problemumgehung: Verwenden Sie stattdessen den Alphakanal. In Ihrem Skript habe ich die Alpha-Werte auf 0,25 bzw. 0,75 gesetzt und mithilfe eines greater than 0.5Knotens visuell bestätigt, dass der Alpha-Kanal linear interpoliert ist.
Möglicherweise könnten auch andere Attribute wie UV verwendet werden.
Ich fürchte, eine kononische Erklärung ist mir ein Rätsel, aber hier ist ein Thread, der das Problem diskutiert. Die Problemumgehung basiert auf der verknüpften Antwort
https://github.com/KhronosGroup/glTF-Blender-IO/issues/542#issuecomment-569361267