godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
86.81k stars 19.43k forks source link

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

Open scgm0 opened 10 months ago

scgm0 commented 10 months ago

Godot version

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

System information

Godot v4.2.dev.mono (75de1ca76) - 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 commented 10 months ago

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

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 commented 9 months ago

reason for issue confirmed here (I believe) https://github.com/godotengine/godot/issues/82351#issuecomment-1735493143

clayjohn commented 9 months ago

This is essentially the same issue as https://github.com/godotengine/godot/issues/82351

Calinou commented 9 months ago

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: https://github.com/godotengine/godot/blob/251fb83d536a96110790bbf85b3fa50e5a8e2b7c/servers/movie_writer/movie_writer.cpp#L172-L196

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 commented 9 months ago

@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 commented 9 months ago

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 commented 9 months ago

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 commented 2 months ago

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.