Fix: Cycles blackbody renders wrong with OSL and ACEScg

OSL only supports a fixed number of color space, so detect a few common
ones and set those. This makes functions like blackbody work correctly.

Pull Request: https://projects.blender.org/blender/blender/pulls/145755
This commit is contained in:
Brecht Van Lommel
2025-08-31 15:41:35 +02:00
parent 76a446deba
commit 19e845b91e
5 changed files with 75 additions and 11 deletions

View File

@@ -899,6 +899,9 @@ void Camera::set_osl_camera(Scene *scene,
const std::string &bytecode)
{
#ifdef WITH_OSL
/* Ensure shading system exists before we try to load a shader. */
scene->osl_manager->shading_system_init(scene->shader_manager->get_scene_linear_space());
/* Load the shader. */
const char *hash;

View File

@@ -124,7 +124,7 @@ bool OSLManager::need_update() const
void OSLManager::device_update_pre(Device *device, Scene *scene)
{
if (scene->shader_manager->use_osl() || !scene->camera->script_name.empty()) {
shading_system_init();
shading_system_init(scene->shader_manager->get_scene_linear_space());
}
if (!need_update()) {
@@ -343,7 +343,7 @@ void OSLManager::texture_system_free()
}
}
void OSLManager::shading_system_init()
void OSLManager::shading_system_init(ShaderManager::SceneLinearSpace colorspace)
{
/* No need to do anything if we already have shading systems. */
if (!ss_map.empty()) {
@@ -353,7 +353,7 @@ void OSLManager::shading_system_init()
/* create shading system, shared between different renders to reduce memory usage */
const thread_scoped_lock lock(ss_shared_mutex);
foreach_osl_device(device_, [this](Device *sub_device, OSLGlobals *) {
foreach_osl_device(device_, [this, colorspace](Device *sub_device, OSLGlobals *) {
const DeviceType device_type = sub_device->info.type;
if (!ss_shared[device_type]) {
@@ -381,6 +381,21 @@ void OSLManager::shading_system_init()
ss->attribute("searchpath:shader", shader_path);
ss->attribute("greedyjit", 1);
/* OSL doesn't accept an arbitrary space, so support a few specific spaces. */
switch (colorspace) {
case ShaderManager::SceneLinearSpace::Rec709:
ss->attribute("colorspace", OSL::Strings::Rec709);
break;
case ShaderManager::SceneLinearSpace::Rec2020:
ss->attribute("colorspace", OSL::Strings::HDTV);
break;
case ShaderManager::SceneLinearSpace::ACEScg:
ss->attribute("colorspace", OSL::Strings::ACEScg);
break;
case ShaderManager::SceneLinearSpace::Unknown:
break;
}
const char *groupdata_alloc_str = getenv("CYCLES_OSL_GROUPDATA_ALLOC");
if (groupdata_alloc_str) {
ss->attribute("max_optix_groupdata_alloc", atoi(groupdata_alloc_str));
@@ -582,8 +597,6 @@ const char *OSLManager::shader_load_filepath(string filepath)
const char *OSLManager::shader_load_bytecode(const string &hash, const string &bytecode)
{
shading_system_init();
foreach_shading_system(
[hash, bytecode](OSL::ShadingSystem *ss) { ss->LoadMemoryCompiledShader(hash, bytecode); });
@@ -740,7 +753,10 @@ OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph,
return nullptr;
}
/* create query */
/* Ensure shading system exists before we try to load a shader. */
scene->osl_manager->shading_system_init(scene->shader_manager->get_scene_linear_space());
/* Load shader code. */
const char *hash;
if (!filepath.empty()) {

View File

@@ -79,6 +79,8 @@ class OSLManager {
const char *shader_load_filepath(string filepath);
OSLShaderInfo *shader_loaded_info(const string &hash);
void shading_system_init(ShaderManager::SceneLinearSpace colorspace);
OSL::ShadingSystem *get_shading_system(Device *sub_device);
OSL::TextureSystem *get_texture_system();
static void foreach_osl_device(Device *device,
@@ -93,7 +95,6 @@ class OSLManager {
void texture_system_init();
void texture_system_free();
void shading_system_init();
void shading_system_free();
void foreach_shading_system(const std::function<void(OSL::ShadingSystem *)> &callback);

View File

@@ -696,7 +696,7 @@ void ShaderManager::device_update_common(Device * /*device*/,
kfilm->rec709_to_r = make_float4(rec709_to_r);
kfilm->rec709_to_g = make_float4(rec709_to_g);
kfilm->rec709_to_b = make_float4(rec709_to_b);
kfilm->is_rec709 = is_rec709;
kfilm->is_rec709 = scene_linear_space == SceneLinearSpace::Rec709;
}
void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene *scene)
@@ -1011,7 +1011,7 @@ void ShaderManager::init_xyz_transforms()
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;
scene_linear_space = SceneLinearSpace::Rec709;
compute_thin_film_table(xyz_to_rec709);
@@ -1079,9 +1079,46 @@ void ShaderManager::init_xyz_transforms()
rec709_to_r = make_float3(rec709_to_rgb.x);
rec709_to_g = make_float3(rec709_to_rgb.y);
rec709_to_b = make_float3(rec709_to_rgb.z);
is_rec709 = transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.0001f);
compute_thin_film_table(xyz_to_rgb);
const Transform xyz_to_rec2020 = make_transform(1.7166512f,
-0.3556708f,
-0.2533663f,
0.0f,
-0.6666844,
1.6164812f,
0.0157685f,
0.0f,
0.0176399f,
-0.0427706f,
0.9421031f,
0.0f);
const Transform acescg_to_xyz = make_transform(0.652238f,
0.128237f,
0.169983f,
0.0f,
0.267672f,
0.674340f,
0.057988f,
0.0f,
-0.005382f,
0.001369f,
1.093071f,
0.0f);
if (transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.001f)) {
scene_linear_space = SceneLinearSpace::Rec709;
}
else if (transform_equal_threshold(xyz_to_rgb, xyz_to_rec2020, 0.001f)) {
scene_linear_space = SceneLinearSpace::Rec2020;
}
else if (transform_equal_threshold(rgb_to_xyz, acescg_to_xyz, 0.001f)) {
scene_linear_space = SceneLinearSpace::ACEScg;
}
else {
scene_linear_space = SceneLinearSpace::Unknown;
}
#endif
}

View File

@@ -212,6 +212,13 @@ class ShaderManager {
void init_xyz_transforms();
enum class SceneLinearSpace { Rec709, Rec2020, ACEScg, Unknown };
SceneLinearSpace get_scene_linear_space()
{
return scene_linear_space;
}
protected:
ShaderManager();
@@ -235,7 +242,7 @@ class ShaderManager {
float3 rec709_to_r;
float3 rec709_to_g;
float3 rec709_to_b;
bool is_rec709;
SceneLinearSpace scene_linear_space;
vector<float> thin_film_table;
template<std::size_t n>