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

Support Linear Color Space for 2D rendering to ease Unity migration #82154

Closed
ghost opened this issue Sep 22, 2023 · 4 comments
Closed

Support Linear Color Space for 2D rendering to ease Unity migration #82154

ghost opened this issue Sep 22, 2023 · 4 comments

Comments

@ghost
Copy link

ghost commented Sep 22, 2023

Godot version

4.2

System information

All

Issue description

Godot supports linear color space rendering for 3D[*] but not 2D. Unity supports linear rendering for 2D:

LinearRendering-ColorSpaceSetting

With the recent spike of interest in migrating 2D projects from Unity to Godot, supporting linear rendering for 2D will ease the migration of 2D games that expect the highest quality blending and lighting.

[*] Not all Godot 3D renderers support linear color space, such as the GLES2 renderer in the 3.x branch. Perhaps they should. The only platform that doesn't support linear rendering "for free" with hardware is the web because there's no way to make an HTML canvas get the free linear-to-gamma space conversion, so shaders must be used. But Godot already does the shader-based linear-to-gamma conversion for high quality web 3D and may as well offer the option to do it for high quality 2D now. Unity's web player does the shader conversion for 2D and 3D as well.

Steps to reproduce

N/A

Minimal reproduction project

N/A

@Calinou
Copy link
Member

Calinou commented Sep 22, 2023

HDR rendering is now supported in 2D with Vulkan-based renderers since 4.2.dev3. You can find a detailed description here: #80215

[*] Not all Godot 3D renderers support linear color space, such as the GLES2 renderer in the 3.x branch. Perhaps they should

Godot 3.x GLES3 uses linear color rendering in 3D, but it's poorly supported on mobile devices and web platforms. This is why Godot 4.x GLES3 is purely sRGB with no HDR capabilities (also for performance reasons). In general, Godot 3.x GLES3 was high-end-oriented while Godot 4.x GLES3 is low-end-oriented. The new high-end-oriented renderers are all based on modern graphics APIs (Vulkan and soon Direct3D 12).

To make things worse, there is no standard way to render with HDR output when using OpenGL (which makes HDR rendering more valuable to have).

@ghost
Copy link
Author

ghost commented Sep 23, 2023

HDR rendering is now supported in 2D with Vulkan-based renderers

This is nice, but:

(1.) Many of us want identical blending and colors on all platforms in either 2D or 3D for non-HDR, which is what Unity offers with its default gamma-to-linear-to-gamma non-HDR workflow. (Godot 3.x GLES3 3D offers the same gamma-to-linear-to-gamma non-HDR workflow on all platforms, even web builds.) But Godot 3D projects still usually use the 2D renderer for UI, and this creates confusion because, say, the game's logo doesn't blend to the same colors in 2D as in 3D.

(2.) Many of us want to migrate Unity 2D linear color projects to Godot and have the lights and textures blend the same. Imagine if the Hollow Knight people migrated to Godot and had to redo all the dark scenes to look OK with blending in sRGB gamma space instead of linear gamma space, which is the Unity 2D default. (And sRGB gamma space blending never looks as good no matter how much one tweaks it, which is the whole point of doing blending the mathematically correct way in linear space.)

(3.) Many of us do not want HDR, because an HDR TV is blindingly bright in a dark room at night when it actually switches to HDR mode. And HDR adds extra heat and power consumption to TVs while increasing OLED burn-in or backlight wear. HDR kills the battery life of the comparatively few mobile devices that support it. Many of us see HDR as a gimmick just like those 3D TVs that required the 3D glasses that appeared after the first Avatar came out.

Furthermore, Vulkan has poor interaction with the Windows DWM, causing higher latency and stuttering in windowed mode, which is why the Chrome team decided not to support it as a backend on Windows and why DX11/DX12 is highly preferable on Windows. You (Calinou) seem to be one Godot's better informed devs on Windows-specific issues, such as how MS blesses DXGI swap chains with lower latency and better smoothness, especially when rendering non-fullscreen. And non-fullscreen rendering is the default workflow during the thousands of hours we gamedevs spend iterating in the editor. NVidia drivers now have an option to promote OpenGL apps to DXGI swapchains and I like to do this for the Godot OpenGL renderers, but it's not without issues, especially when VRR is thrown in the mix... but I won't digress further. I look forward to the Godot DX12 renderer but having the Godot web player render the same colors as the DX12 renderer, which is what the Unity web player does, would make Godot much easier to use. And easier to use is ultimately The Godot Way.

So HDR for Vulkan is nice but what Unity migraters need is the same gamma-to-linear-to-gamma non-HDR workflow for 2D which is supported "for free" by fixed function hardware everywhere except the web. (WebGL1/WebGL2/WebGPU all support gamma-to-linear conversion for free when reading textures into a shader but don't (yet) support free linear-to-gamma conversion when writing from the shader to the canvas framebuffer. Free hardware linear-to-gamma can be done when writing to offscreen renderbuffers but then the renderbuffer has to be sampled/blitted to the canvas.

Finally, for the sake of others who read this issue, I want to be perfectly clear what I mean about gamma-to-linear-to-gamma non-HDR workflow. Godot sources have this glsl shader fallback to perform the two conversions when the fixed function "free" hardware can't be used:

vec3 linear_to_srgb(vec3 color) {
	//if going to srgb, clamp from 0 to 1.
	color = clamp(color, vec3(0.0), vec3(1.0));
	const vec3 a = vec3(0.055f);
	return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}

vec3 srgb_to_linear(vec3 color) {
	return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045)));
}

Source: https://github.com/godotengine/godot/blob/465d4c1d959ffd752e5d62b6d178e8984dcef66e/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl

So for example if a 32-bit sRGB RGBA8 texture is loaded from a PNG, it is stored in memory as 8 bits per channel in the usual non-linear sRGB gamma space. When loaded into a shader the "free" fixed function hardware should do srgb_to_linear automatically on the R, G, and B channels (alpha is always linear and never converted). So for example the RGBA color #BCBCBC80 in texture memory would be converted to roughly (0.5,0.5,0.5,0.5) in the shader. And if the shader computes an output color of (0.5,0.5,0.5,0.5), it will be re-encoded by linear_to_srgb to approximately #BCBCBC80 when written to a 32 bit sRGB framebuffer.

(Note: in the above GLSL from the Godot sources it would probably be more efficient to use a 256-entry table when doing the conversion for 8 bit per channel colors. Unless there's some reason a LUT can't be used that I'm not thinking of right now... I haven't actually tried to write the LUT code and then benchmark it.)

@QbieShay
Copy link
Contributor

Hello @dev-muppet, welcome to the Godot github!

Since this issue looks more like a proposal for adding a new feature to the engine, please use our proposals repository, we have a better template that you can fill, detailing your usecase like you did in the comments, so it's all in one place and easier for us to keep track of.

Also, please detail your usecase not only in comparison to Unity and in the context of a Unity migration, but also why do you want to use this option in general. This is crucial for us to understand how this feature benefits Godot users, and not only people migrating from Unity, and thus will make it easier for both us and you to work together on a solution.
Ultimately we'll need to evaluate the cost-benefit of adding this and having all this information will help.

Proposal repo: https://github.com/godotengine/godot-proposals/issues

Issues on this repository are meant to keep track of bugs.

@Calinou
Copy link
Member

Calinou commented Sep 26, 2023

Closing, as feature proposals should be discussed on the Godot proposals repository. This repository is now used for bug reports only.

Make sure to follow the proposal template when opening a new proposal – don't just copy and paste the text you wrote in this issue.

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

No branches or pull requests

2 participants