Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure MovieWriter output is in gamma space when using HDR 2D #92496

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions core/io/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions core/io/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Image> rgbe_to_srgb();
Ref<Image> get_image_from_mipmap(int p_mipamp) const;
Expand Down
8 changes: 7 additions & 1 deletion doc/classes/Image.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</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" />
Expand Down Expand Up @@ -574,7 +580,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>
Expand Down
1 change: 1 addition & 0 deletions doc/classes/Viewport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
5 changes: 5 additions & 0 deletions doc/classes/ViewportTexture.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
4 changes: 4 additions & 0 deletions servers/movie_writer/movie_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions servers/rendering/renderer_viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/renderer_viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading