diff --git a/core/io/image.cpp b/core/io/image.cpp index 5498b448d71a..44418fc69ea1 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -3475,6 +3475,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges); ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha); ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear); + ClassDB::bind_method(D_METHOD("linear_to_srgb"), &Image::linear_to_srgb); ClassDB::bind_method(D_METHOD("normal_map_to_xy"), &Image::normal_map_to_xy); ClassDB::bind_method(D_METHOD("rgbe_to_srgb"), &Image::rgbe_to_srgb); ClassDB::bind_method(D_METHOD("bump_map_to_normal_map", "bump_scale"), &Image::bump_map_to_normal_map, DEFVAL(1.0)); @@ -3741,6 +3742,37 @@ void Image::srgb_to_linear() { } } +void Image::linear_to_srgb() { + if (data.size() == 0) { + return; + } + + static const uint8_t lin2srgb[256] = { 0, 12, 21, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 66, 68, 70, 73, 75, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 94, 96, 97, 99, 100, 102, 103, 104, 106, 107, 109, 110, 111, 112, 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 161, 162, 163, 164, 165, 165, 166, 167, 168, 168, 169, 170, 171, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255 }; + + ERR_FAIL_COND(format != FORMAT_RGB8 && format != FORMAT_RGBA8); + + if (format == FORMAT_RGBA8) { + int len = data.size() / 4; + uint8_t *data_ptr = data.ptrw(); + + for (int i = 0; i < len; i++) { + data_ptr[(i << 2) + 0] = lin2srgb[data_ptr[(i << 2) + 0]]; + data_ptr[(i << 2) + 1] = lin2srgb[data_ptr[(i << 2) + 1]]; + data_ptr[(i << 2) + 2] = lin2srgb[data_ptr[(i << 2) + 2]]; + } + + } else if (format == FORMAT_RGB8) { + int len = data.size() / 3; + uint8_t *data_ptr = data.ptrw(); + + for (int i = 0; i < len; i++) { + data_ptr[(i * 3) + 0] = lin2srgb[data_ptr[(i * 3) + 0]]; + data_ptr[(i * 3) + 1] = lin2srgb[data_ptr[(i * 3) + 1]]; + data_ptr[(i * 3) + 2] = lin2srgb[data_ptr[(i * 3) + 2]]; + } + } +} + void Image::premultiply_alpha() { if (data.size() == 0) { return; diff --git a/core/io/image.h b/core/io/image.h index daddfac59d7d..6ed042092a22 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -381,6 +381,7 @@ class Image : public Resource { void fix_alpha_edges(); void premultiply_alpha(); void srgb_to_linear(); + void linear_to_srgb(); void normal_map_to_xy(); Ref rgbe_to_srgb(); Ref get_image_from_mipmap(int p_mipamp) const; diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 68d4deaffdb1..cae525fce97f 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -305,6 +305,12 @@ Returns [code]true[/code] if all the image's pixels have an alpha value of 0. Returns [code]false[/code] if any pixel has an alpha value higher than 0. + + + + Converts the entire image from the linear colorspace to the sRGB colorspace. Only works on images with [constant FORMAT_RGB8] or [constant FORMAT_RGBA8] formats. + + @@ -574,7 +580,7 @@ - Converts the raw data from the sRGB colorspace to a linear scale. + Converts the raw data from the sRGB colorspace to a linear scale. Only works on images with [constant FORMAT_RGB8] or [constant FORMAT_RGBA8] formats. diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index b288ee7ff63a..edfb140346dd 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -102,6 +102,7 @@ await RenderingServer.frame_post_draw $Viewport.get_texture().get_image().save_png("user://Screenshot.png") [/codeblock] + [b]Note:[/b] When [member use_hdr_2d] is [code]true[/code] the returned texture will be an HDR image encoded in linear space. diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml index ba2352ab610f..f6840d6b0952 100644 --- a/doc/classes/ViewportTexture.xml +++ b/doc/classes/ViewportTexture.xml @@ -8,6 +8,11 @@ To get a [ViewportTexture] in code, use the [method Viewport.get_texture] method on the target viewport. [b]Note:[/b] A [ViewportTexture] is always local to its scene (see [member Resource.resource_local_to_scene]). If the scene root is not ready, it may return incorrect data (see [signal Node.ready]). [b]Note:[/b] Instantiating scenes containing a high-resolution [ViewportTexture] may cause noticeable stutter. + [b]Note:[/b] When using a [Viewport] with [member Viewport.use_hdr_2d] set to [code]true[/code] the returned texture will be an HDR image encoded in linear space. This may look darker than normal when displayed directly on screen. To convert to gamma space, you can do the following: + [codeblock] + img.convert(Image.FORMAT_RGBA8) + imb.linear_to_srgb() + [/codeblock] https://godotengine.org/asset-library/asset/2807 diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp index 9df05ba94af2..aebed4b432de 100644 --- a/servers/movie_writer/movie_writer.cpp +++ b/servers/movie_writer/movie_writer.cpp @@ -185,6 +185,10 @@ void MovieWriter::add_frame() { RID main_vp_rid = RenderingServer::get_singleton()->viewport_find_from_screen_attachment(DisplayServer::MAIN_WINDOW_ID); RID main_vp_texture = RenderingServer::get_singleton()->viewport_get_texture(main_vp_rid); Ref vp_tex = RenderingServer::get_singleton()->texture_2d_get(main_vp_texture); + if (RenderingServer::get_singleton()->viewport_is_using_hdr_2d(main_vp_rid)) { + vp_tex->convert(Image::FORMAT_RGBA8); + vp_tex->linear_to_srgb(); + } RenderingServer::get_singleton()->viewport_set_measure_render_time(main_vp_rid, true); cpu_time += RenderingServer::get_singleton()->viewport_get_measured_render_time_cpu(main_vp_rid); diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 884f8adb8c4e..4af89b218e83 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -1270,6 +1270,13 @@ void RendererViewport::viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d RSG::texture_storage->render_target_set_use_hdr(viewport->render_target, p_use_hdr_2d); } +bool RendererViewport::viewport_is_using_hdr_2d(RID p_viewport) const { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_NULL_V(viewport, false); + + return viewport->use_hdr_2d; +} + void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_NULL(viewport); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index b36fc7f57ff6..bf97905f8694 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -262,6 +262,8 @@ class RendererViewport { void viewport_set_transparent_background(RID p_viewport, bool p_enabled); void viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr_2d); + bool viewport_is_using_hdr_2d(RID p_viewport) const; + void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform); void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 164ec3cc09fe..b0a68fbe3533 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -639,6 +639,7 @@ class RenderingServerDefault : public RenderingServer { FUNC3(viewport_set_canvas_transform, RID, RID, const Transform2D &) FUNC2(viewport_set_transparent_background, RID, bool) FUNC2(viewport_set_use_hdr_2d, RID, bool) + FUNC1RC(bool, viewport_is_using_hdr_2d, RID) FUNC2(viewport_set_snap_2d_transforms_to_pixel, RID, bool) FUNC2(viewport_set_snap_2d_vertices_to_pixel, RID, bool) diff --git a/servers/rendering_server.h b/servers/rendering_server.h index e15dba43536f..332432792129 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -934,6 +934,7 @@ class RenderingServer : public Object { virtual void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) = 0; virtual void viewport_set_transparent_background(RID p_viewport, bool p_enabled) = 0; virtual void viewport_set_use_hdr_2d(RID p_viewport, bool p_use_hdr) = 0; + virtual bool viewport_is_using_hdr_2d(RID p_viewport) const = 0; virtual void viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) = 0; virtual void viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) = 0;