Merge pull request #51780 from BastiaanOlij/output_linear_gles2
Convert output of GLES2 to linear color space
This commit is contained in:
commit
46ad2560a1
8 changed files with 94 additions and 9 deletions
|
@ -228,7 +228,7 @@
|
|||
[b]Note:[/b] Requires [member usage] to be set to [constant USAGE_3D] or [constant USAGE_3D_NO_EFFECTS], since HDR is not supported for 2D.
|
||||
</member>
|
||||
<member name="keep_3d_linear" type="bool" setter="set_keep_3d_linear" getter="get_keep_3d_linear" default="false">
|
||||
If [code]true[/code], the result after 3D rendering will not have a linear to sRGB color conversion applied. This is important when the viewport is used as a render target where the result is used as a texture on a 3D object rendered in another viewport. It is also important if the viewport is used to create data that is not color based (noise, heightmaps, pickmaps, etc.). Do not enable this when the viewport is used as a texture on a 2D object or if the viewport is your final output.
|
||||
If [code]true[/code], the result after 3D rendering will not have a linear to sRGB color conversion applied. This is important when the viewport is used as a render target where the result is used as a texture on a 3D object rendered in another viewport. It is also important if the viewport is used to create data that is not color based (noise, heightmaps, pickmaps, etc.). Do not enable this when the viewport is used as a texture on a 2D object or if the viewport is your final output. For the GLES2 driver this will convert the sRGB output to linear, this should only be used for VR plugins that require input in linear color space!
|
||||
</member>
|
||||
<member name="msaa" type="int" setter="set_msaa" getter="get_msaa" enum="Viewport.MSAA" default="0">
|
||||
The multisample anti-aliasing mode. A higher number results in smoother edges at the cost of significantly worse performance. A value of 4 is best unless targeting very high-end systems.
|
||||
|
|
|
@ -403,6 +403,7 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
|
|||
canvas->_set_texture_rect_mode(true);
|
||||
|
||||
canvas->state.canvas_shader.set_custom_shader(0);
|
||||
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::LINEAR_TO_SRGB, rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]);
|
||||
canvas->state.canvas_shader.bind();
|
||||
|
||||
canvas->canvas_begin();
|
||||
|
@ -421,6 +422,8 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
|
|||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
canvas->canvas_end();
|
||||
|
||||
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::LINEAR_TO_SRGB, false);
|
||||
}
|
||||
|
||||
void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
|
||||
|
|
|
@ -2655,6 +2655,11 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
|
|||
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false);
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false);
|
||||
if (storage->frame.current_rt) {
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::OUTPUT_LINEAR, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]);
|
||||
} else {
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::OUTPUT_LINEAR, false);
|
||||
}
|
||||
storage->shaders.copy.bind();
|
||||
storage->shaders.copy.set_uniform(CopyShaderGLES2::MULTIPLIER, p_energy);
|
||||
|
||||
|
@ -2678,6 +2683,7 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
|
|||
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false);
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false);
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
|
||||
storage->shaders.copy.set_conditional(CopyShaderGLES2::OUTPUT_LINEAR, false);
|
||||
}
|
||||
|
||||
void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p_cam_projection) {
|
||||
|
@ -3312,7 +3318,15 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
|
|||
}
|
||||
|
||||
if (!env || env->bg_mode != VS::ENV_BG_KEEP) {
|
||||
glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
|
||||
if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]) {
|
||||
// convert to linear here
|
||||
Color linear_color = clear_color.to_linear();
|
||||
glClearColor(linear_color.r, linear_color.g, linear_color.b, linear_color.a);
|
||||
|
||||
// leave clear_color in sRGB as most of the render pipeline remains in sRGB color space until writing out to frag_color
|
||||
} else {
|
||||
glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
|
@ -3416,6 +3430,13 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
|
|||
state.default_bg = Color(0, 0, 0, 1); //black as default background for interior
|
||||
}
|
||||
|
||||
// make sure we set our output mode correctly
|
||||
if (storage->frame.current_rt) {
|
||||
state.scene_shader.set_conditional(SceneShaderGLES2::OUTPUT_LINEAR, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]);
|
||||
} else {
|
||||
state.scene_shader.set_conditional(SceneShaderGLES2::OUTPUT_LINEAR, false);
|
||||
}
|
||||
|
||||
// render opaque things first
|
||||
render_list.sort_by_key(false);
|
||||
_render_render_list(render_list.elements, render_list.element_count, cam_transform, p_cam_projection, p_eye, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, false, false);
|
||||
|
@ -3519,6 +3540,9 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
|
|||
storage->_copy_screen();
|
||||
}
|
||||
#endif
|
||||
|
||||
// return to default
|
||||
state.scene_shader.set_conditional(SceneShaderGLES2::OUTPUT_LINEAR, false);
|
||||
}
|
||||
|
||||
void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
|
||||
|
@ -3736,6 +3760,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
|
|||
}
|
||||
|
||||
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true);
|
||||
state.scene_shader.set_conditional(SceneShaderGLES2::OUTPUT_LINEAR, false); // just in case, should be false already
|
||||
|
||||
_render_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, 0, RID(), nullptr, 0, bias, normal_bias, flip_facing, false, true);
|
||||
|
||||
|
|
|
@ -701,5 +701,11 @@ FRAGMENT_SHADER_CODE
|
|||
//use lighting
|
||||
#endif
|
||||
|
||||
#ifdef LINEAR_TO_SRGB
|
||||
// regular Linear -> SRGB conversion
|
||||
vec3 a = vec3(0.055);
|
||||
color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, vec3(lessThan(color.rgb, vec3(0.0031308))));
|
||||
#endif
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
|
|
|
@ -187,5 +187,10 @@ void main() {
|
|||
color.rgb *= multiplier;
|
||||
#endif
|
||||
|
||||
#ifdef OUTPUT_LINEAR
|
||||
// sRGB -> linear
|
||||
color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), vec3(lessThan(color.rgb, vec3(0.04045))));
|
||||
#endif
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
|
|
|
@ -2307,6 +2307,11 @@ FRAGMENT_SHADER_CODE
|
|||
|
||||
#endif //unshaded
|
||||
|
||||
#ifdef OUTPUT_LINEAR
|
||||
// sRGB -> linear
|
||||
gl_FragColor.rgb = mix(pow((gl_FragColor.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), gl_FragColor.rgb * (1.0 / 12.92), vec3(lessThan(gl_FragColor.rgb, vec3(0.04045))));
|
||||
#endif
|
||||
|
||||
#else // not RENDER_DEPTH
|
||||
//depth render
|
||||
#ifdef USE_RGBA_SHADOWS
|
||||
|
|
|
@ -334,15 +334,49 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re
|
|||
RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
|
||||
ERR_FAIL_COND(!rt);
|
||||
|
||||
Size2 win_size = OS::get_singleton()->get_window_size();
|
||||
if (rt->external.fbo != 0) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
|
||||
if (rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]) {
|
||||
// We need to add an sRGB conversion here as we kept our buffer linear (+ a little tone mapping).
|
||||
|
||||
canvas->_set_texture_rect_mode(true);
|
||||
|
||||
canvas->state.canvas_shader.set_custom_shader(0);
|
||||
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES3::LINEAR_TO_SRGB, true);
|
||||
canvas->state.canvas_shader.bind();
|
||||
|
||||
canvas->canvas_begin();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
// render to our framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
|
||||
|
||||
// output our texture
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
if (rt->external.fbo != 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, rt->external.color);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, rt->color);
|
||||
}
|
||||
|
||||
canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1));
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
canvas->canvas_end();
|
||||
|
||||
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES3::LINEAR_TO_SRGB, false);
|
||||
} else {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
|
||||
// No conversion needed, take the faster approach
|
||||
|
||||
Size2 win_size = OS::get_singleton()->get_window_size();
|
||||
if (rt->external.fbo != 0) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
|
||||
} else {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
|
||||
}
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
|
||||
glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height - p_screen_rect.position.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
|
||||
glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height - p_screen_rect.position.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
|
||||
|
|
|
@ -855,6 +855,13 @@ FRAGMENT_SHADER_CODE
|
|||
|
||||
//use lighting
|
||||
#endif
|
||||
|
||||
#ifdef LINEAR_TO_SRGB
|
||||
// regular Linear -> SRGB conversion
|
||||
vec3 a = vec3(0.055);
|
||||
color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308)));
|
||||
#endif
|
||||
|
||||
//color.rgb *= color.a;
|
||||
frag_color = color;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue