Fix Cycles blackbody shader not taking into account OpenColorIO config
Keep the existing Rec.709 fit and convert to other colorspace if needed, it seems accurate enough in practice, and keeps the same performance for the default case.
This commit is contained in:
@@ -23,7 +23,7 @@ ccl_device_noinline void svm_node_blackbody(KernelGlobals kg,
|
||||
/* Input */
|
||||
float temperature = stack_load_float(stack, temperature_offset);
|
||||
|
||||
float3 color_rgb = svm_math_blackbody_color(temperature);
|
||||
float3 color_rgb = rec709_to_rgb(kg, svm_math_blackbody_color_rec709(temperature));
|
||||
|
||||
stack_store_float3(stack, col_offset, color_rgb);
|
||||
}
|
||||
|
@@ -1111,7 +1111,8 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg,
|
||||
|
||||
if (intensity > CLOSURE_WEIGHT_CUTOFF) {
|
||||
float3 blackbody_tint = stack_load_float3(stack, node.w);
|
||||
float3 bb = blackbody_tint * intensity * svm_math_blackbody_color(T);
|
||||
float3 bb = blackbody_tint * intensity *
|
||||
rec709_to_rgb(kg, svm_math_blackbody_color_rec709(T));
|
||||
emission_setup(sd, bb);
|
||||
}
|
||||
}
|
||||
|
@@ -189,10 +189,8 @@ ccl_device float svm_math(NodeMathType type, float a, float b, float c)
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float3 svm_math_blackbody_color(float t)
|
||||
ccl_device float3 svm_math_blackbody_color_rec709(float t)
|
||||
{
|
||||
/* TODO(lukas): Reimplement in XYZ. */
|
||||
|
||||
/* Calculate color in range 800..12000 using an approximation
|
||||
* a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
|
||||
* Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
|
||||
|
@@ -1117,13 +1117,18 @@ typedef struct KernelFilm {
|
||||
float4 xyz_to_g;
|
||||
float4 xyz_to_b;
|
||||
float4 rgb_to_y;
|
||||
/* Rec709 to rendering color space. */
|
||||
float4 rec709_to_r;
|
||||
float4 rec709_to_g;
|
||||
float4 rec709_to_b;
|
||||
int is_rec709;
|
||||
|
||||
int pass_bake_primitive;
|
||||
int pass_bake_differential;
|
||||
|
||||
int use_approximate_shadow_catcher;
|
||||
|
||||
int pad1, pad2;
|
||||
int pad1;
|
||||
} KernelFilm;
|
||||
static_assert_align(KernelFilm, 16);
|
||||
|
||||
|
@@ -14,6 +14,15 @@ ccl_device float3 xyz_to_rgb(KernelGlobals kg, float3 xyz)
|
||||
dot(float4_to_float3(kernel_data.film.xyz_to_b), xyz));
|
||||
}
|
||||
|
||||
ccl_device float3 rec709_to_rgb(KernelGlobals kg, float3 rec709)
|
||||
{
|
||||
return (kernel_data.film.is_rec709) ?
|
||||
rec709 :
|
||||
make_float3(dot(float4_to_float3(kernel_data.film.rec709_to_r), rec709),
|
||||
dot(float4_to_float3(kernel_data.film.rec709_to_g), rec709),
|
||||
dot(float4_to_float3(kernel_data.film.rec709_to_b), rec709));
|
||||
}
|
||||
|
||||
ccl_device float linear_rgb_to_gray(KernelGlobals kg, float3 c)
|
||||
{
|
||||
return dot(c, float4_to_float3(kernel_data.film.rgb_to_y));
|
||||
|
@@ -579,6 +579,10 @@ void ShaderManager::device_update_common(Device * /*device*/,
|
||||
kfilm->xyz_to_g = float3_to_float4(xyz_to_g);
|
||||
kfilm->xyz_to_b = float3_to_float4(xyz_to_b);
|
||||
kfilm->rgb_to_y = float3_to_float4(rgb_to_y);
|
||||
kfilm->rec709_to_r = float3_to_float4(rec709_to_r);
|
||||
kfilm->rec709_to_g = float3_to_float4(rec709_to_g);
|
||||
kfilm->rec709_to_b = float3_to_float4(rec709_to_b);
|
||||
kfilm->is_rec709 = is_rec709;
|
||||
}
|
||||
|
||||
void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene)
|
||||
@@ -740,6 +744,11 @@ float ShaderManager::linear_rgb_to_gray(float3 c)
|
||||
return dot(c, rgb_to_y);
|
||||
}
|
||||
|
||||
float3 ShaderManager::rec709_to_scene_linear(float3 c)
|
||||
{
|
||||
return make_float3(dot(rec709_to_r, c), dot(rec709_to_g, c), dot(rec709_to_b, c));
|
||||
}
|
||||
|
||||
string ShaderManager::get_cryptomatte_materials(Scene *scene)
|
||||
{
|
||||
string manifest = "{";
|
||||
@@ -802,11 +811,29 @@ void ShaderManager::init_xyz_transforms()
|
||||
{
|
||||
/* Default to ITU-BT.709 in case no appropriate transform found.
|
||||
* Note XYZ here is defined as having a D65 white point. */
|
||||
xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f);
|
||||
xyz_to_g = make_float3(-0.9692660f, 1.8760108f, 0.0415560f);
|
||||
xyz_to_b = make_float3(0.0556434f, -0.2040259f, 1.0572252f);
|
||||
const Transform xyz_to_rec709 = make_transform(3.2404542f,
|
||||
-1.5371385f,
|
||||
-0.4985314f,
|
||||
0.0f,
|
||||
-0.9692660f,
|
||||
1.8760108f,
|
||||
0.0415560f,
|
||||
0.0f,
|
||||
0.0556434f,
|
||||
-0.2040259f,
|
||||
1.0572252f,
|
||||
0.0f);
|
||||
|
||||
xyz_to_r = float4_to_float3(xyz_to_rec709.x);
|
||||
xyz_to_g = float4_to_float3(xyz_to_rec709.y);
|
||||
xyz_to_b = float4_to_float3(xyz_to_rec709.z);
|
||||
rgb_to_y = make_float3(0.2126729f, 0.7151522f, 0.0721750f);
|
||||
|
||||
rec709_to_r = make_float3(1.0f, 0.0f, 0.0f);
|
||||
rec709_to_g = make_float3(0.0f, 1.0f, 0.0f);
|
||||
rec709_to_b = make_float3(0.0f, 0.0f, 1.0f);
|
||||
is_rec709 = true;
|
||||
|
||||
#ifdef WITH_OCIO
|
||||
/* Get from OpenColorO config if it has the required roles. */
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
@@ -857,6 +884,12 @@ void ShaderManager::init_xyz_transforms()
|
||||
|
||||
const Transform rgb_to_xyz = transform_inverse(xyz_to_rgb);
|
||||
rgb_to_y = float4_to_float3(rgb_to_xyz.y);
|
||||
|
||||
const Transform rec709_to_rgb = xyz_to_rgb * transform_inverse(xyz_to_rec709);
|
||||
rec709_to_r = float4_to_float3(rec709_to_rgb.x);
|
||||
rec709_to_g = float4_to_float3(rec709_to_rgb.y);
|
||||
rec709_to_b = float4_to_float3(rec709_to_rgb.z);
|
||||
is_rec709 = transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.0001f);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -208,6 +208,7 @@ class ShaderManager {
|
||||
static void free_memory();
|
||||
|
||||
float linear_rgb_to_gray(float3 c);
|
||||
float3 rec709_to_scene_linear(float3 c);
|
||||
|
||||
string get_cryptomatte_materials(Scene *scene);
|
||||
|
||||
@@ -239,6 +240,10 @@ class ShaderManager {
|
||||
float3 xyz_to_g;
|
||||
float3 xyz_to_b;
|
||||
float3 rgb_to_y;
|
||||
float3 rec709_to_r;
|
||||
float3 rec709_to_g;
|
||||
float3 rec709_to_b;
|
||||
bool is_rec709;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -5763,7 +5763,9 @@ BlackbodyNode::BlackbodyNode() : ShaderNode(get_node_type())
|
||||
void BlackbodyNode::constant_fold(const ConstantFolder &folder)
|
||||
{
|
||||
if (folder.all_inputs_constant()) {
|
||||
folder.make_constant(svm_math_blackbody_color(temperature));
|
||||
const float3 rgb_rec709 = svm_math_blackbody_color_rec709(temperature);
|
||||
const float3 rgb = folder.scene->shader_manager->rec709_to_scene_linear(rgb_rec709);
|
||||
folder.make_constant(rgb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -285,6 +285,21 @@ ccl_device_inline bool operator!=(const Transform &A, const Transform &B)
|
||||
return !(A == B);
|
||||
}
|
||||
|
||||
ccl_device_inline bool transform_equal_threshold(const Transform &A,
|
||||
const Transform &B,
|
||||
const float threshold)
|
||||
{
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; y < 4; y++) {
|
||||
if (fabsf(A[x][y] - B[x][y]) > threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 transform_get_column(const Transform *t, int column)
|
||||
{
|
||||
return make_float3(t->x[column], t->y[column], t->z[column]);
|
||||
|
Reference in New Issue
Block a user