Skip to content

Commit

Permalink
Color: Rename to_srgb/to_linear to include base color space
Browse files Browse the repository at this point in the history
This helps reduce confusion around sRGB <> Linear conversions by making
both input and output color spaces explicit.
  • Loading branch information
akien-mga committed Apr 13, 2022
1 parent 8904731 commit 46ef521
Show file tree
Hide file tree
Showing 15 changed files with 68 additions and 68 deletions.
2 changes: 1 addition & 1 deletion core/io/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3276,7 +3276,7 @@ Ref<Image> Image::rgbe_to_srgb() {

for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
new_image->set_pixel(col, row, get_pixel(col, row).to_srgb());
new_image->set_pixel(col, row, get_pixel(col, row).linear_to_srgb());
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/math/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,14 @@ struct _NO_DISCARD_ Color {
return res;
}

_FORCE_INLINE_ Color to_linear() const {
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
r < 0.04045f ? r * (1.0 / 12.92) : Math::pow((r + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
g < 0.04045f ? g * (1.0 / 12.92) : Math::pow((g + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
b < 0.04045f ? b * (1.0 / 12.92) : Math::pow((b + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
a);
}
_FORCE_INLINE_ Color to_srgb() const {
_FORCE_INLINE_ Color linear_to_srgb() const {
return Color(
r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f,
g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f,
Expand Down
4 changes: 2 additions & 2 deletions core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1656,8 +1656,8 @@ static void _register_variant_builtin_methods() {
bind_method(Color, darkened, sarray("amount"), varray());
bind_method(Color, blend, sarray("over"), varray());
bind_method(Color, get_luminance, sarray(), varray());
bind_method(Color, to_linear, sarray(), varray());
bind_method(Color, to_srgb, sarray(), varray());
bind_method(Color, srgb_to_linear, sarray(), varray());
bind_method(Color, linear_to_srgb, sarray(), varray());

bind_method(Color, is_equal_approx, sarray("to"), varray());

Expand Down
26 changes: 13 additions & 13 deletions doc/classes/Color.xml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@
<description>
Returns the luminance of the color in the [code][0.0, 1.0][/code] range.
This is useful when determining light or dark color. Colors with a luminance smaller than 0.5 can be generally considered dark.
[b]Note:[/b] [method get_luminance] relies on the colour being in the linear color space to return an accurate relative luminance value. If the color is in the sRGB color space, use [method to_linear] to convert it to the linear color space first.
[b]Note:[/b] [method get_luminance] relies on the colour being in the linear color space to return an accurate relative luminance value. If the color is in the sRGB color space, use [method srgb_to_linear] to convert it to the linear color space first.
</description>
</method>
<method name="get_named_color" qualifiers="static">
Expand Down Expand Up @@ -321,6 +321,18 @@
[/codeblocks]
</description>
</method>
<method name="linear_to_srgb" qualifiers="const">
<return type="Color" />
<description>
Returns the color converted to the [url=https://en.wikipedia.org/wiki/SRGB]sRGB[/url] color space. This assumes the original color is in the linear color space. See also [method srgb_to_linear] which performs the opposite operation.
</description>
</method>
<method name="srgb_to_linear" qualifiers="const">
<return type="Color" />
<description>
Returns the color converted to the linear color space. This assumes the original color is in the sRGB color space. See also [method linear_to_srgb] which performs the opposite operation.
</description>
</method>
<method name="to_abgr32" qualifiers="const">
<return type="int" />
<description>
Expand Down Expand Up @@ -405,12 +417,6 @@
[/codeblocks]
</description>
</method>
<method name="to_linear" qualifiers="const">
<return type="Color" />
<description>
Returns the color converted to the linear color space. This assumes the original color is in the sRGB color space. See also [method to_srgb] which performs the opposite operation.
</description>
</method>
<method name="to_rgba32" qualifiers="const">
<return type="int" />
<description>
Expand Down Expand Up @@ -443,12 +449,6 @@
[/codeblocks]
</description>
</method>
<method name="to_srgb" qualifiers="const">
<return type="Color" />
<description>
Returns the color converted to the [url=https://en.wikipedia.org/wiki/SRGB]sRGB[/url] color space. This assumes the original color is in the linear color space. See also [method to_linear] which performs the opposite operation.
</description>
</method>
</methods>
<members>
<member name="a" type="float" setter="" getter="" default="1.0">
Expand Down
18 changes: 9 additions & 9 deletions modules/gltf/gltf_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3272,7 +3272,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Dictionary mr;
{
Array arr;
const Color c = material->get_albedo().to_linear();
const Color c = material->get_albedo().srgb_to_linear();
arr.push_back(c.r);
arr.push_back(c.g);
arr.push_back(c.b);
Expand Down Expand Up @@ -3473,7 +3473,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}

if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
const Color c = material->get_emission().to_srgb();
const Color c = material->get_emission().linear_to_srgb();
Array arr;
arr.push_back(c.r);
arr.push_back(c.g);
Expand Down Expand Up @@ -3555,7 +3555,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (sgm.has("diffuseFactor")) {
const Array &arr = sgm["diffuseFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb();
spec_gloss->diffuse_factor = c;
material->set_albedo(spec_gloss->diffuse_factor);
}
Expand Down Expand Up @@ -3586,7 +3586,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (mr.has("baseColorFactor")) {
const Array &arr = mr["baseColorFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb();
material->set_albedo(c);
}

Expand Down Expand Up @@ -3653,7 +3653,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (d.has("emissiveFactor")) {
const Array &arr = d["emissiveFactor"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);

material->set_emission(c);
Expand Down Expand Up @@ -3737,11 +3737,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
}
for (int32_t y = 0; y < r_spec_gloss->spec_gloss_img->get_height(); y++) {
for (int32_t x = 0; x < r_spec_gloss->spec_gloss_img->get_width(); x++) {
const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).to_linear();
const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).srgb_to_linear();
Color specular = Color(specular_pixel.r, specular_pixel.g, specular_pixel.b);
specular *= r_spec_gloss->specular_factor;
Color diffuse = Color(1.0f, 1.0f, 1.0f);
diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).to_linear();
diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).srgb_to_linear();
float metallic = 0.0f;
Color base_color;
spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic);
Expand All @@ -3758,7 +3758,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
mr.g = 1.0f - mr.g;
rm_img->set_pixel(x, y, mr);
if (r_spec_gloss->diffuse_img.is_valid()) {
r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.to_srgb());
r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.linear_to_srgb());
}
}
}
Expand Down Expand Up @@ -4626,7 +4626,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
if (d.has("color")) {
const Array &arr = d["color"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
light->color = c;
}
if (d.has("intensity")) {
Expand Down
2 changes: 1 addition & 1 deletion modules/hdr/image_loader_hdr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_f
ptr[2] * exp / 255.0);

if (p_force_linear) {
c = c.to_linear();
c = c.srgb_to_linear();
}

*(uint32_t *)ptr = c.to_rgbe9995();
Expand Down
4 changes: 2 additions & 2 deletions modules/tinyexr/image_loader_tinyexr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool
}

if (p_force_linear) {
color = color.to_linear();
color = color.srgb_to_linear();
}

*row_w++ = Math::make_half_float(color.r);
Expand Down Expand Up @@ -261,7 +261,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool
}

if (p_force_linear) {
color = color.to_linear();
color = color.srgb_to_linear();
}

*row_w++ = color.r;
Expand Down
2 changes: 1 addition & 1 deletion scene/3d/lightmap_gi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
Light3D *light = lights_found[i].light;
Transform3D xf = lights_found[i].xform;

Color linear_color = light->get_color().to_linear();
Color linear_color = light->get_color().srgb_to_linear();
if (Object::cast_to<DirectionalLight3D>(light)) {
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
//ambient
if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
color = color.to_linear();
color = color.srgb_to_linear();

scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
Expand All @@ -793,7 +793,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
} else {
float energy = environment_get_ambient_light_energy(p_render_data->environment);
Color color = environment_get_ambient_light_color(p_render_data->environment);
color = color.to_linear();
color = color.srgb_to_linear();
scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
Expand Down Expand Up @@ -829,7 +829,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);

Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear();
Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
float fog_energy = environment_get_fog_light_energy(p_render_data->environment);

scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
Expand All @@ -844,7 +844,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
} else {
scene_state.ubo.use_ambient_light = true;
Color clear_color = p_default_bg_color;
clear_color = clear_color.to_linear();
clear_color = clear_color.srgb_to_linear();
scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
Expand Down Expand Up @@ -1391,7 +1391,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
clear_color.b *= bg_energy;
if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
} break;
case RS::ENV_BG_COLOR: {
Expand All @@ -1401,7 +1401,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
clear_color.b *= bg_energy;
if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
} break;
case RS::ENV_BG_SKY: {
Expand Down Expand Up @@ -1520,7 +1520,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co

Vector<Color> c;
{
Color cc = clear_color.to_linear();
Color cc = clear_color.srgb_to_linear();
if (using_separate_specular) {
cc.a = 0; //subsurf scatter must be 0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
/*
if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
*/
} break;
Expand All @@ -608,7 +608,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
/*
if (render_buffers_has_volumetric_fog(p_render_data->render_buffers) || environment_is_fog_enabled(p_render_data->environment)) {
draw_sky_fog_only = true;
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
}
*/
} break;
Expand Down Expand Up @@ -723,10 +723,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
{
// regular forward for now
Vector<Color> c;
c.push_back(clear_color.to_linear()); // our render buffer
c.push_back(clear_color.srgb_to_linear()); // our render buffer
if (render_buffer) {
if (render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
c.push_back(clear_color.to_linear()); // our resolve buffer
c.push_back(clear_color.srgb_to_linear()); // our resolve buffer
}
if (using_subpass_post_process) {
c.push_back(Color()); // our 2D buffer we're copying into
Expand Down Expand Up @@ -1616,7 +1616,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
//ambient
if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
color = color.to_linear();
color = color.srgb_to_linear();

scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
Expand All @@ -1626,7 +1626,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
} else {
float energy = environment_get_ambient_light_energy(p_render_data->environment);
Color color = environment_get_ambient_light_color(p_render_data->environment);
color = color.to_linear();
color = color.srgb_to_linear();
scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
Expand Down Expand Up @@ -1657,7 +1657,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);

Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear();
Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
float fog_energy = environment_get_fog_light_energy(p_render_data->environment);

scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
Expand All @@ -1672,7 +1672,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data,
} else {
scene_state.ubo.use_ambient_light = true;
Color clear_color = p_default_bg_color;
clear_color = clear_color.to_linear();
clear_color = clear_color.srgb_to_linear();
scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
Expand Down
10 changes: 5 additions & 5 deletions servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ void RendererSceneGIRD::SDFGI::update_probes(RendererSceneEnvironmentRD *p_env,

if (p_env->background == RS::ENV_BG_CLEAR_COLOR) {
push_constant.sky_mode = SDFGIShader::IntegratePushConstant::SKY_MODE_COLOR;
Color c = storage->get_default_clear_color().to_linear();
Color c = storage->get_default_clear_color().srgb_to_linear();
push_constant.sky_color[0] = c.r;
push_constant.sky_color[1] = c.g;
push_constant.sky_color[2] = c.b;
Expand Down Expand Up @@ -1469,7 +1469,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re
lights[idx].direction[1] = dir.y;
lights[idx].direction[2] = dir.z;
Color color = storage->light_get_color(li->light);
color = color.to_linear();
color = color.srgb_to_linear();
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
Expand Down Expand Up @@ -1514,7 +1514,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re
lights[idx].position[1] = pos.y;
lights[idx].position[2] = pos.z;
Color color = storage->light_get_color(li->light);
color = color.to_linear();
color = color.srgb_to_linear();
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
Expand Down Expand Up @@ -1953,7 +1953,7 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32
lights[idx].position[1] = pos.y;
lights[idx].position[2] = pos.z;
Color color = storage->light_get_color(li->light);
color = color.to_linear();
color = color.srgb_to_linear();
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
Expand Down Expand Up @@ -2396,7 +2396,7 @@ void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, c
l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
Color color = storage->light_get_color(light).to_linear();
Color color = storage->light_get_color(light).srgb_to_linear();
l.color[0] = color.r;
l.color[1] = color.g;
l.color[2] = color.b;
Expand Down
Loading

0 comments on commit 46ef521

Please sign in to comment.