summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-08-19 12:08:40 +0200
committerRémi Verschelde <rverschelde@gmail.com>2024-08-19 12:08:40 +0200
commitf4037d6f6cc7d400d39a25332df33e11fbf8d983 (patch)
treed3c6f1b4025af2c4a7ee430a946763130ea1da56
parent824a97120e8a84a56abd305294a4ce57c871a134 (diff)
parent3b9d074fd76b06eba8b70d4bb366ee68b3cc1b9e (diff)
downloadredot-engine-f4037d6f6cc7d400d39a25332df33e11fbf8d983.tar.gz
Merge pull request #92496 from clayjohn/HDR-2D-sRGB
Ensure MovieWriter output is in gamma space when using HDR 2D
-rw-r--r--core/io/image.cpp32
-rw-r--r--core/io/image.h1
-rw-r--r--doc/classes/Image.xml8
-rw-r--r--doc/classes/Viewport.xml1
-rw-r--r--doc/classes/ViewportTexture.xml5
-rw-r--r--servers/movie_writer/movie_writer.cpp4
-rw-r--r--servers/rendering/renderer_viewport.cpp7
-rw-r--r--servers/rendering/renderer_viewport.h2
-rw-r--r--servers/rendering/rendering_server_default.h1
-rw-r--r--servers/rendering_server.h1
10 files changed, 61 insertions, 1 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp
index b35d405662..499364826d 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -3564,6 +3564,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));
@@ -3831,6 +3832,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 d55cc39dbb..cc285dabe3 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -383,6 +383,7 @@ public:
void fix_alpha_edges();
void premultiply_alpha();
void srgb_to_linear();
+ void linear_to_srgb();
void normal_map_to_xy();
Ref<Image> rgbe_to_srgb();
Ref<Image> get_image_from_mipmap(int p_mipmap) const;
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index db7796778e..e254fd56e9 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -321,6 +321,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.
</description>
</method>
+ <method name="linear_to_srgb">
+ <return type="void" />
+ <description>
+ 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.
+ </description>
+ </method>
<method name="load">
<return type="int" enum="Error" />
<param index="0" name="path" type="String" />
@@ -590,7 +596,7 @@
<method name="srgb_to_linear">
<return type="void" />
<description>
- 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.
</description>
</method>
</methods>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index f57185ae87..b24f26a764 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.
</description>
</method>
<method name="get_viewport_rid" qualifiers="const">
diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml
index ba2352ab61..f6840d6b09 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]
</description>
<tutorials>
<link title="GUI in 3D Viewport Demo">https://godotengine.org/asset-library/asset/2807</link>
diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp
index 9df05ba94a..aebed4b432 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<Image> 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 1049cb63cd..7e45eba1de 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -1271,6 +1271,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 b36fc7f57f..bf97905f86 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -262,6 +262,8 @@ public:
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 6e195a8002..039f038b8f 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -639,6 +639,7 @@ public:
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 8450cb0198..86d9d5dbd3 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -924,6 +924,7 @@ public:
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;