Convert output of GLES2 to linear color space if keep_3d_linear is enabled

This commit is contained in:
Bastiaan Olij
2021-08-17 14:55:37 +10:00
parent 2370fe5c26
commit 73722f3c65
8 changed files with 94 additions and 9 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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;
}