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

Movie mode recording in 2D HDR is not as good as expected. #81301

Closed
scgm0 opened this issue Sep 4, 2023 · 8 comments · Fixed by #92496
Closed

Movie mode recording in 2D HDR is not as good as expected. #81301

scgm0 opened this issue Sep 4, 2023 · 8 comments · Fixed by #92496

Comments

@scgm0
Copy link
Contributor

scgm0 commented Sep 4, 2023

Godot version

v4.2.dev.mono.custom_build [75de1ca]

System information

Godot v4.2.dev.mono (75de1ca) - Arch Linux #0~20230903.g20dcd95 SMP PREEMPT_DYNAMIC Sun Sep 3 05:16:45 UTC - Wayland - Vulkan (Mobile) - dedicated NVIDIA GeForce GTX 1650 (nvidia; 535.104.05) - Intel(R) Core(TM) i5-9300H CPU @ 2.40GHz (8 Threads)

Issue description

2D HDR on, no restarting:
图片
2D HDR on, restarting:
图片
Movie mode recording output:
图片
(I have run out of Deepl translations, please understand...)

Steps to reproduce

  1. Turn on 2D HDR, and simply configure the scene to highlight the 2D HDR effect.
  2. Record video with movie mode.

Minimal reproduction project

N/A

@torcado194
Copy link

torcado194 commented Sep 9, 2023

I've confirmed this on v4.2.dev3.official [013e8e3]

I tried looking into a solution to this for a few days but couldn't get anything working.
My guess is that this is due to the tonemapping godot does on the output, as mentioned here:

Godot does not support high dynamic range output yet. It can only perform lighting in HDR and tonemap the result to a low dynamic range image.

... the issue being that this tonemapping is done for the window viewport but not for the texture sent into the movie_writer, but I'm not sure.


In the meantine, you can work around this issue by using a shader to manually convert from linear to sRGB space for movie mode only:

shader_type canvas_item;
global uniform bool MOVIE;
uniform sampler2D screen_texture : hint_screen_texture;

void fragment() {
	COLOR = texture(screen_texture, SCREEN_UV);
	if(MOVIE){
		COLOR.rgb = pow(COLOR.rgb, vec3(1.0/2.2));
	}
}
func _ready():
	if OS.has_feature('movie'):
		RenderingServer.global_shader_parameter_set("MOVIE", true)

(this will cause the displayed image to be incorrect, but the recorded movie will be closer to the intended result)

without workaround with workaround
image (correct) display in-editor image display while recording movie
image movie recording without workaround image movie recording with workaround

Here's an MRP with the issue and the workaround:

hdr-movie-mode-mrp.zip

@torcado194
Copy link

reason for issue confirmed here (I believe)
#82351 (comment)

@clayjohn
Copy link
Member

This is essentially the same issue as #82351

@Calinou
Copy link
Member

Calinou commented Sep 27, 2023

It should be possible for MovieWriter to automatically perform the linear-to-sRGB conversion depending on whether 2D HDR is enabled. Relevant code is here:

void MovieWriter::add_frame() {
const int movie_time_seconds = Engine::get_singleton()->get_frames_drawn() / fps;
const String movie_time = vformat("%s:%s:%s",
String::num(movie_time_seconds / 3600).pad_zeros(2),
String::num((movie_time_seconds % 3600) / 60).pad_zeros(2),
String::num(movie_time_seconds % 60).pad_zeros(2));
#ifdef DEBUG_ENABLED
DisplayServer::get_singleton()->window_set_title(vformat("MovieWriter: Frame %d (time: %s) - %s (DEBUG)", Engine::get_singleton()->get_frames_drawn(), movie_time, project_name));
#else
DisplayServer::get_singleton()->window_set_title(vformat("MovieWriter: Frame %d (time: %s) - %s", Engine::get_singleton()->get_frames_drawn(), movie_time, project_name));
#endif
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);
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);
cpu_time += RenderingServer::get_singleton()->get_frame_setup_time_cpu();
gpu_time += RenderingServer::get_singleton()->viewport_get_measured_render_time_gpu(main_vp_rid);
AudioDriverDummy::get_dummy_singleton()->mix_audio(mix_rate / fps, audio_mix_buffer.ptr());
write_frame(vp_tex, audio_mix_buffer.ptr());
}

There is one potential concern however: in the long run, some people may desire to have movie output that's written in linear space so it can be integrated in compositing software (you'd also need the output to be in OpenEXR and have high dynamic range). That said, given MovieWriter can't write to OpenEXR yet, I think we can always perform the conversion for now.

@torcado194
Copy link

@Calinou I couldn't figure out what methods to use to convert a texture from linear to sRGB, if any exist. There are automatic conversion methods in Color, and some shaders with sRGB conversion options, but nothing for textures that I could find. I saw that some TextureStorage methods have an srgb parameter, such as TextureStorage::texture_get_rd_texture, but I couldn't get that working in that callback, and even if I did it doesn't seem like it would do what I'm looking for.

If you have any pointers there, that would be appreciated!

@Calinou
Copy link
Member

Calinou commented Sep 27, 2023

You will probably need to loop over the image's individual pixels and convert them to sRGB using the Color function. I'm not sure if we have a single function that does this on an entire image.

@torcado194
Copy link

Hm, alright. I would be worried about performance at that point, perhaps a shader is the best solution for now. Though, I haven't tested it.
Thank you for the input!

@h0lley
Copy link

h0lley commented Apr 30, 2024

I think rendering a video in sRGB color space is by far the more common and expected use case.

we've been trying out movie maker mode recently to render a trailer. despite movie maker mode seemingly being the ideal application for that, we gave up on using it because our game uses 2D HDR and the results were unexpected.

alternatively to automatic conversion, a warning hint when enabling movie mode combined with a link to docs explaining how to convert your video could be a satisfactory solution, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants