diff options
Diffstat (limited to 'servers/rendering/renderer_rd')
51 files changed, 2197 insertions, 612 deletions
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index 4a98cf0831..6ad3556969 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h index feafd4c2db..7f6750fa7e 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.h +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index cf943901d4..4a19519995 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1315,6 +1315,111 @@ void EffectsRD::bokeh_dof_raster(const BokehBuffers &p_buffers, bool p_dof_far, } } +void EffectsRD::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection) { + // Downsample and deinterleave the depth buffer for SSAO and SSIL + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + int downsample_pipeline = SS_EFFECTS_DOWNSAMPLE; + bool use_mips = p_ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || p_ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM; + + if (p_ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && p_ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_HALF; + } else if (use_mips) { + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_MIPMAP; + } + + bool use_half_size = false; + bool use_full_mips = false; + + if (p_ssao_half_size && p_ssil_half_size) { + downsample_pipeline++; + use_half_size = true; + } else if (p_ssao_half_size != p_ssil_half_size) { + if (use_mips) { + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS; + use_full_mips = true; + } else { + // Only need the first two mipmaps, but the cost to generate the next two is trivial + // TODO investigate the benefit of a shader version to generate only 2 mips + downsample_pipeline = SS_EFFECTS_DOWNSAMPLE_MIPMAP; + use_mips = true; + } + } + + int depth_index = use_half_size ? 1 : 0; + + RD::get_singleton()->draw_command_begin_label("Downsample Depth"); + if (p_invalidate_uniform_set || use_full_mips != ss_effects.used_full_mips_last_frame || use_half_size != ss_effects.used_half_size_last_frame || use_mips != ss_effects.used_mips_last_frame) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_depth_mipmaps[depth_index + 1]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_depth_mipmaps[depth_index + 2]); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 2; + u.ids.push_back(p_depth_mipmaps[depth_index + 3]); + uniforms.push_back(u); + } + if (use_full_mips) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 3; + u.ids.push_back(p_depth_mipmaps[4]); + uniforms.push_back(u); + } + ss_effects.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, use_full_mips ? 6 : 2), 2); + } + + float depth_linearize_mul = -p_projection.matrix[3][2]; + float depth_linearize_add = p_projection.matrix[2][2]; + if (depth_linearize_mul * depth_linearize_add < 0) { + depth_linearize_add = -depth_linearize_add; + } + + ss_effects.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); + ss_effects.downsample_push_constant.z_near = depth_linearize_mul; + ss_effects.downsample_push_constant.z_far = depth_linearize_add; + if (ss_effects.downsample_push_constant.orthogonal) { + ss_effects.downsample_push_constant.z_near = p_projection.get_z_near(); + ss_effects.downsample_push_constant.z_far = p_projection.get_z_far(); + } + ss_effects.downsample_push_constant.pixel_size[0] = 1.0 / p_full_screen_size.x; + ss_effects.downsample_push_constant.pixel_size[1] = 1.0 / p_full_screen_size.y; + ss_effects.downsample_push_constant.radius_sq = 1.0; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ss_effects.pipelines[downsample_pipeline]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[depth_index + 0]), 1); + if (use_mips) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ss_effects.downsample_uniform_set, 2); + } + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ss_effects.downsample_push_constant, sizeof(SSEffectsDownsamplePushConstant)); + + Size2i size(MAX(1, p_full_screen_size.x >> (use_half_size ? 2 : 1)), MAX(1, p_full_screen_size.y >> (use_half_size ? 2 : 1))); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE); + + ss_effects.used_full_mips_last_frame = use_mips; + ss_effects.used_full_mips_last_frame = use_full_mips; + ss_effects.used_half_size_last_frame = use_half_size; +} + void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) { RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { @@ -1341,82 +1446,12 @@ void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> RD::get_singleton()->compute_list_add_barrier(p_compute_list); } -void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) { +void EffectsRD::generate_ssao(RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->draw_command_begin_label("SSAO"); + memset(&ssao.gather_push_constant, 0, sizeof(SSAOGatherPushConstant)); /* FIRST PASS */ - // Downsample and deinterleave the depth buffer. - { - RD::get_singleton()->draw_command_begin_label("Downsample Depth"); - if (p_invalidate_uniform_sets) { - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 0; - u.ids.push_back(p_depth_mipmaps[1]); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 1; - u.ids.push_back(p_depth_mipmaps[2]); - uniforms.push_back(u); - } - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = 2; - u.ids.push_back(p_depth_mipmaps[3]); - uniforms.push_back(u); - } - r_downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2); - } - - float depth_linearize_mul = -p_projection.matrix[3][2]; - float depth_linearize_add = p_projection.matrix[2][2]; - if (depth_linearize_mul * depth_linearize_add < 0) { - depth_linearize_add = -depth_linearize_add; - } - - ssao.downsample_push_constant.orthogonal = p_projection.is_orthogonal(); - ssao.downsample_push_constant.z_near = depth_linearize_mul; - ssao.downsample_push_constant.z_far = depth_linearize_add; - if (ssao.downsample_push_constant.orthogonal) { - ssao.downsample_push_constant.z_near = p_projection.get_z_near(); - ssao.downsample_push_constant.z_far = p_projection.get_z_far(); - } - ssao.downsample_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; - ssao.downsample_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; - ssao.downsample_push_constant.radius_sq = p_settings.radius * p_settings.radius; - - int downsample_pipeline = SSAO_DOWNSAMPLE; - if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { - downsample_pipeline = SSAO_DOWNSAMPLE_HALF; - } else if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { - downsample_pipeline = SSAO_DOWNSAMPLE_MIPMAP; - } - - if (p_settings.half_size) { - downsample_pipeline++; - } - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[downsample_pipeline]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1); - if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, r_downsample_uniform_set, 2); - } - RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant)); - - Size2i size(MAX(1, p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)), MAX(1, p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1))); - - RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1); - RD::get_singleton()->compute_list_add_barrier(compute_list); - RD::get_singleton()->draw_command_end_label(); // Downsample SSAO - } + RD::get_singleton()->draw_command_begin_label("Process Screen Space Ambient Occlusion"); /* SECOND PASS */ // Sample SSAO { @@ -1469,7 +1504,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; u.binding = 0; - u.ids.push_back(ssao.mirror_sampler); + u.ids.push_back(default_sampler); u.ids.push_back(p_depth_mipmaps_texture); uniforms.push_back(u); } @@ -1484,7 +1519,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; - u.ids.push_back(ssao.gather_constants_buffer); + u.ids.push_back(ss_effects.gather_constants_buffer); uniforms.push_back(u); } r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0); @@ -1574,6 +1609,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep for (int pass = 0; pass < blur_passes; pass++) { int blur_pipeline = SSAO_BLUR_PASS; if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) { + blur_pipeline = SSAO_BLUR_PASS_SMART; if (pass < blur_passes - 2) { blur_pipeline = SSAO_BLUR_PASS_WIDE; } else { @@ -1591,7 +1627,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_slices[i]), 0); } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_slices[i], ssao.mirror_sampler), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_slices[i], ss_effects.mirror_sampler), 0); } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_pong_slices[i]), 1); @@ -1599,7 +1635,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao_pong_slices[i]), 0); } else { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_pong_slices[i], ssao.mirror_sampler), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ao_pong_slices[i], ss_effects.mirror_sampler), 0); } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao_slices[i]), 1); } @@ -1649,12 +1685,305 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::get_singleton()->draw_command_end_label(); // Interleave } RD::get_singleton()->draw_command_end_label(); //SSAO - RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_TRANSFER); //wait for upcoming transfer + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //wait for upcoming transfer int zero[1] = { 0 }; RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier } +void EffectsRD::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); + if ((p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_projection_uniform_set, 3); + + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; + } + + ssil.gather_push_constant.pass_coord_offset[0] = i % 2; + ssil.gather_push_constant.pass_coord_offset[1] = i / 2; + ssil.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x; + ssil.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y; + ssil.gather_push_constant.pass = i; + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, _get_compute_uniform_set_from_image_pair(p_ssil_slices[i], p_edges_slices[i]), 2); + RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssil.gather_push_constant, sizeof(SSILGatherPushConstant)); + + Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + + RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1); + } + RD::get_singleton()->compute_list_add_barrier(p_compute_list); +} + +void EffectsRD::screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ssil, const Vector<RID> p_ssil_slices, RID p_ssil_pong, const Vector<RID> p_ssil_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set) { + RD::get_singleton()->draw_command_begin_label("Process Screen Space Indirect Lighting"); + //Store projection info before starting the compute list + SSILProjectionUniforms projection_uniforms; + store_camera(p_last_projection, projection_uniforms.inv_last_frame_projection_matrix); + + RD::get_singleton()->buffer_update(ssil.projection_uniform_buffer, 0, sizeof(SSILProjectionUniforms), &projection_uniforms); + + memset(&ssil.gather_push_constant, 0, sizeof(SSILGatherPushConstant)); + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + { + RD::get_singleton()->draw_command_begin_label("Gather Samples"); + ssil.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x; + ssil.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y; + + ssil.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssil.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + float tan_half_fov_x = 1.0 / p_projection.matrix[0][0]; + float tan_half_fov_y = 1.0 / p_projection.matrix[1][1]; + ssil.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0; + ssil.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0; + ssil.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0; + ssil.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y; + ssil.gather_push_constant.z_near = p_projection.get_z_near(); + ssil.gather_push_constant.z_far = p_projection.get_z_far(); + ssil.gather_push_constant.is_orthogonal = p_projection.is_orthogonal(); + + ssil.gather_push_constant.half_screen_pixel_size_x025[0] = ssil.gather_push_constant.half_screen_pixel_size[0] * 0.25; + ssil.gather_push_constant.half_screen_pixel_size_x025[1] = ssil.gather_push_constant.half_screen_pixel_size[1] * 0.25; + + ssil.gather_push_constant.radius = p_settings.radius; + float radius_near_limit = (p_settings.radius * 1.2f); + if (p_settings.quality <= RS::ENV_SSIL_QUALITY_LOW) { + radius_near_limit *= 1.50f; + + if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + ssil.gather_push_constant.radius *= 0.8f; + } + } + radius_near_limit /= tan_half_fov_y; + ssil.gather_push_constant.intensity = p_settings.intensity * Math_PI; + ssil.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from); + ssil.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0; + ssil.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit; + ssil.gather_push_constant.neg_inv_radius = -1.0 / ssil.gather_push_constant.radius; + ssil.gather_push_constant.normal_rejection_amount = p_settings.normal_rejection; + + ssil.gather_push_constant.load_counter_avg_div = 9.0 / float((p_settings.quarter_screen_size.x) * (p_settings.quarter_screen_size.y) * 255); + ssil.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target; + + ssil.gather_push_constant.quality = MAX(0, p_settings.quality - 1); + ssil.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1; + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(default_mipmap_sampler); + u.ids.push_back(p_diffuse); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 1; + u.ids.push_back(ssil.projection_uniform_buffer); + uniforms.push_back(u); + } + r_projection_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0), 3); + } + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(default_sampler); + u.ids.push_back(p_depth_mipmaps_texture); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 1; + u.ids.push_back(p_normal_buffer); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.ids.push_back(ss_effects.gather_constants_buffer); + uniforms.push_back(u); + } + r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0), 0); + } + + if (p_invalidate_uniform_sets) { + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 0; + u.ids.push_back(p_ssil_pong); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 1; + u.ids.push_back(default_sampler); + u.ids.push_back(p_importance_map); + uniforms.push_back(u); + } + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(ssil.importance_map_load_counter); + uniforms.push_back(u); + } + r_importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 2), 1); + } + + if (p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) { + RD::get_singleton()->draw_command_begin_label("Generate Importance Map"); + ssil.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssil.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + ssil.importance_map_push_constant.intensity = p_settings.intensity * Math_PI; + //base pass + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_BASE]); + gather_ssil(compute_list, p_ssil_pong_slices, p_edges_slices, p_settings, true, r_gather_uniform_set, r_importance_map_uniform_set, r_projection_uniform_set); + //generate importance map + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GENERATE_IMPORTANCE_MAP]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + // process Importance Map A + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPA]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map_pong), 1); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + // process Importance Map B + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPB]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_importance_map_pong), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_importance_map), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssil.counter_uniform_set, 2); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.quarter_screen_size.x, p_settings.quarter_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + RD::get_singleton()->draw_command_end_label(); // Importance Map + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_ADAPTIVE]); + } else { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER]); + } + + gather_ssil(compute_list, p_ssil_slices, p_edges_slices, p_settings, false, r_gather_uniform_set, r_importance_map_uniform_set, r_projection_uniform_set); + RD::get_singleton()->draw_command_end_label(); //Gather + } + + { + RD::get_singleton()->draw_command_begin_label("Edge Aware Blur"); + ssil.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness; + ssil.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_settings.half_screen_size.x; + ssil.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_settings.half_screen_size.y; + + int blur_passes = p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? p_settings.blur_passes : 1; + + for (int pass = 0; pass < blur_passes; pass++) { + int blur_pipeline = SSIL_BLUR_PASS; + if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { + blur_pipeline = SSIL_BLUR_PASS_SMART; + if (pass < blur_passes - 2) { + blur_pipeline = SSIL_BLUR_PASS_WIDE; + } + } + + for (int i = 0; i < 4; i++) { + if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { + continue; + } + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]); + if (pass % 2 == 0) { + if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ssil_slices[i], ss_effects.mirror_sampler), 0); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ssil_pong_slices[i]), 1); + } else { + if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_pong_slices[i]), 0); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_and_sampler(p_ssil_pong_slices[i], ss_effects.mirror_sampler), 0); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ssil_slices[i]), 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_edges_slices[i]), 2); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.blur_push_constant, sizeof(SSILBlurPushConstant)); + + int x_groups = (p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1)); + int y_groups = (p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1); + if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) { + RD::get_singleton()->compute_list_add_barrier(compute_list); + } + } + } + + RD::get_singleton()->draw_command_end_label(); // Blur + } + + { + RD::get_singleton()->draw_command_begin_label("Interleave Buffers"); + ssil.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness; + ssil.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x; + ssil.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y; + ssil.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2); + + int interleave_pipeline = SSIL_INTERLEAVE_HALF; + if (p_settings.quality == RS::ENV_SSIL_QUALITY_LOW) { + interleave_pipeline = SSIL_INTERLEAVE; + } else if (p_settings.quality >= RS::ENV_SSIL_QUALITY_MEDIUM) { + interleave_pipeline = SSIL_INTERLEAVE_SMART; + } + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[interleave_pipeline]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination), 0); + + if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil), 1); + } else { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ssil_pong), 1); + } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_edges), 2); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.interleave_push_constant, sizeof(SSILInterleavePushConstant)); + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + RD::get_singleton()->draw_command_end_label(); // Interleave + } + + RD::get_singleton()->draw_command_end_label(); // SSIL + + RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); + + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier +} + void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) { roughness_limiter.push_constant.screen_size[0] = p_size.x; roughness_limiter.push_constant.screen_size[1] = p_size.y; @@ -2173,63 +2502,36 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } if (!prefer_raster_effects) { - // Initialize ssao - - RD::SamplerState sampler; - sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; - sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; - sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; - sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; - sampler.max_lod = 4; - - ssao.mirror_sampler = RD::get_singleton()->sampler_create(sampler); - - uint32_t pipeline = 0; - { - Vector<String> ssao_modes; - ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define USE_HALF_SIZE\n"); - ssao_modes.push_back("\n#define GENERATE_MIPS\n"); - ssao_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE"); - ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n"); - ssao_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE"); - - ssao.downsample_shader.initialize(ssao_modes); - - ssao.downsample_shader_version = ssao.downsample_shader.version_create(); - - for (int i = 0; i <= SSAO_DOWNSAMPLE_HALF_RES_HALF; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, i)); - pipeline++; - } - } { - Vector<String> ssao_modes; - - ssao_modes.push_back("\n"); - ssao_modes.push_back("\n#define SSAO_BASE\n"); - ssao_modes.push_back("\n#define ADAPTIVE\n"); - - ssao.gather_shader.initialize(ssao_modes); - - ssao.gather_shader_version = ssao.gather_shader.version_create(); - - for (int i = SSAO_GATHER; i <= SSAO_GATHER_ADAPTIVE; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER)); - pipeline++; + // Initialize depth buffer for screen space effects + Vector<String> downsampler_modes; + downsampler_modes.push_back("\n"); + downsampler_modes.push_back("\n#define USE_HALF_SIZE\n"); + downsampler_modes.push_back("\n#define GENERATE_MIPS\n"); + downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE\n"); + downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n"); + downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE\n"); + downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define GENERATE_FULL_MIPS"); + + ss_effects.downsample_shader.initialize(downsampler_modes); + + ss_effects.downsample_shader_version = ss_effects.downsample_shader.version_create(); + + for (int i = 0; i < SS_EFFECTS_MAX; i++) { + ss_effects.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, i)); } - ssao.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSAOGatherConstants)); - SSAOGatherConstants gather_constants; + ss_effects.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSEffectsGatherConstants)); + SSEffectsGatherConstants gather_constants; const int sub_pass_count = 5; for (int pass = 0; pass < 4; pass++) { for (int subPass = 0; subPass < sub_pass_count; subPass++) { int a = pass; + int b = subPass; + int spmap[5]{ 0, 1, 4, 3, 2 }; - int b = spmap[subPass]; + b = spmap[subPass]; float ca, sa; float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f; @@ -2246,72 +2548,105 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } } - RD::get_singleton()->buffer_update(ssao.gather_constants_buffer, 0, sizeof(SSAOGatherConstants), &gather_constants); + RD::get_singleton()->buffer_update(ss_effects.gather_constants_buffer, 0, sizeof(SSEffectsGatherConstants), &gather_constants); } + { - Vector<String> ssao_modes; - ssao_modes.push_back("\n#define GENERATE_MAP\n"); - ssao_modes.push_back("\n#define PROCESS_MAPA\n"); - ssao_modes.push_back("\n#define PROCESS_MAPB\n"); + // Initialize ssao - ssao.importance_map_shader.initialize(ssao_modes); + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST; + sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler.max_lod = 4; - ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); + ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler); - for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); + uint32_t pipeline = 0; + { + Vector<String> ssao_modes; - pipeline++; - } - ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); - int zero[1] = { 0 }; - RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); - RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter"); + ssao_modes.push_back("\n"); + ssao_modes.push_back("\n#define SSAO_BASE\n"); + ssao_modes.push_back("\n#define ADAPTIVE\n"); - Vector<RD::Uniform> uniforms; + ssao.gather_shader.initialize(ssao_modes); + + ssao.gather_shader_version = ssao.gather_shader.version_create(); + + for (int i = 0; i <= SSAO_GATHER_ADAPTIVE; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i)); + pipeline++; + } + } { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 0; - u.ids.push_back(ssao.importance_map_load_counter); - uniforms.push_back(u); + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define GENERATE_MAP\n"); + ssao_modes.push_back("\n#define PROCESS_MAPA\n"); + ssao_modes.push_back("\n#define PROCESS_MAPB\n"); + + ssao.importance_map_shader.initialize(ssao_modes); + + ssao.importance_map_shader_version = ssao.importance_map_shader.version_create(); + + for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP)); + + pipeline++; + } + ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero); + RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter"); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(ssao.importance_map_load_counter); + uniforms.push_back(u); + } + ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); + RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set"); } - ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2); - RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set"); - } - { - Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MODE_NON_SMART\n"); - ssao_modes.push_back("\n#define MODE_SMART\n"); - ssao_modes.push_back("\n#define MODE_WIDE\n"); + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_WIDE\n"); - ssao.blur_shader.initialize(ssao_modes); + ssao.blur_shader.initialize(ssao_modes); - ssao.blur_shader_version = ssao.blur_shader.version_create(); + ssao.blur_shader_version = ssao.blur_shader.version_create(); - for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); + for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS)); - pipeline++; + pipeline++; + } } - } - { - Vector<String> ssao_modes; - ssao_modes.push_back("\n#define MODE_NON_SMART\n"); - ssao_modes.push_back("\n#define MODE_SMART\n"); - ssao_modes.push_back("\n#define MODE_HALF\n"); - - ssao.interleave_shader.initialize(ssao_modes); - - ssao.interleave_shader_version = ssao.interleave_shader.version_create(); - for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { - ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); - RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); - pipeline++; + { + Vector<String> ssao_modes; + ssao_modes.push_back("\n#define MODE_NON_SMART\n"); + ssao_modes.push_back("\n#define MODE_SMART\n"); + ssao_modes.push_back("\n#define MODE_HALF\n"); + + ssao.interleave_shader.initialize(ssao_modes); + + ssao.interleave_shader_version = ssao.interleave_shader.version_create(); + for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) { + ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE)); + RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i)); + pipeline++; + } } - } - ERR_FAIL_COND(pipeline != SSAO_MAX); + ERR_FAIL_COND(pipeline != SSAO_MAX); + } } if (!prefer_raster_effects) { @@ -2504,6 +2839,79 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } { + Vector<String> ssil_modes; + ssil_modes.push_back("\n"); + ssil_modes.push_back("\n#define SSIL_BASE\n"); + ssil_modes.push_back("\n#define ADAPTIVE\n"); + + ssil.gather_shader.initialize(ssil_modes); + + ssil.gather_shader_version = ssil.gather_shader.version_create(); + + for (int i = SSIL_GATHER; i <= SSIL_GATHER_ADAPTIVE; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.gather_shader.version_get_shader(ssil.gather_shader_version, i)); + } + ssil.projection_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSILProjectionUniforms)); + } + + { + Vector<String> ssil_modes; + ssil_modes.push_back("\n#define GENERATE_MAP\n"); + ssil_modes.push_back("\n#define PROCESS_MAPA\n"); + ssil_modes.push_back("\n#define PROCESS_MAPB\n"); + + ssil.importance_map_shader.initialize(ssil_modes); + + ssil.importance_map_shader_version = ssil.importance_map_shader.version_create(); + + for (int i = SSIL_GENERATE_IMPORTANCE_MAP; i <= SSIL_PROCESS_IMPORTANCE_MAPB; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, i - SSIL_GENERATE_IMPORTANCE_MAP)); + } + ssil.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t)); + int zero[1] = { 0 }; + RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero); + RD::get_singleton()->set_resource_name(ssil.importance_map_load_counter, "Importance Map Load Counter"); + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(ssil.importance_map_load_counter); + uniforms.push_back(u); + } + ssil.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 2), 2); + RD::get_singleton()->set_resource_name(ssil.counter_uniform_set, "Load Counter Uniform Set"); + } + { + Vector<String> ssil_modes; + ssil_modes.push_back("\n#define MODE_NON_SMART\n"); + ssil_modes.push_back("\n#define MODE_SMART\n"); + ssil_modes.push_back("\n#define MODE_WIDE\n"); + + ssil.blur_shader.initialize(ssil_modes); + + ssil.blur_shader_version = ssil.blur_shader.version_create(); + for (int i = SSIL_BLUR_PASS; i <= SSIL_BLUR_PASS_WIDE; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.blur_shader.version_get_shader(ssil.blur_shader_version, i - SSIL_BLUR_PASS)); + } + } + + { + Vector<String> ssil_modes; + ssil_modes.push_back("\n#define MODE_NON_SMART\n"); + ssil_modes.push_back("\n#define MODE_SMART\n"); + ssil_modes.push_back("\n#define MODE_HALF\n"); + + ssil.interleave_shader.initialize(ssil_modes); + + ssil.interleave_shader_version = ssil.interleave_shader.version_create(); + for (int i = SSIL_INTERLEAVE; i <= SSIL_INTERLEAVE_HALF; i++) { + ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, i - SSIL_INTERLEAVE)); + } + } + + { Vector<String> resolve_modes; resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n"); resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n"); @@ -2600,20 +3008,26 @@ EffectsRD::~EffectsRD() { copy.shader.version_free(copy.shader_version); resolve.shader.version_free(resolve.shader_version); specular_merge.shader.version_free(specular_merge.shader_version); + ss_effects.downsample_shader.version_free(ss_effects.downsample_shader_version); ssao.blur_shader.version_free(ssao.blur_shader_version); ssao.gather_shader.version_free(ssao.gather_shader_version); - ssao.downsample_shader.version_free(ssao.downsample_shader_version); ssao.interleave_shader.version_free(ssao.interleave_shader_version); ssao.importance_map_shader.version_free(ssao.importance_map_shader_version); + ssil.blur_shader.version_free(ssil.blur_shader_version); + ssil.gather_shader.version_free(ssil.gather_shader_version); + ssil.interleave_shader.version_free(ssil.interleave_shader_version); + ssil.importance_map_shader.version_free(ssil.importance_map_shader_version); roughness_limiter.shader.version_free(roughness_limiter.shader_version); ssr.shader.version_free(ssr.shader_version); ssr_filter.shader.version_free(ssr_filter.shader_version); ssr_scale.shader.version_free(ssr_scale.shader_version); sss.shader.version_free(sss.shader_version); - RD::get_singleton()->free(ssao.mirror_sampler); - RD::get_singleton()->free(ssao.gather_constants_buffer); + RD::get_singleton()->free(ss_effects.mirror_sampler); + RD::get_singleton()->free(ss_effects.gather_constants_buffer); RD::get_singleton()->free(ssao.importance_map_load_counter); + RD::get_singleton()->free(ssil.importance_map_load_counter); + RD::get_singleton()->free(ssil.projection_uniform_buffer); } copy_to_fb.shader.version_free(copy_to_fb.shader_version); cube_to_dp.shader.version_free(cube_to_dp.shader_version); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 6037127e82..747f2c8941 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -55,11 +55,15 @@ #include "servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/specular_merge.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao_blur.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/ssao_downsample.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil_blur.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/ssil_interleave.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" @@ -399,13 +403,47 @@ private: PipelineCacheRD raster_pipelines[BOKEH_MAX]; } bokeh; + struct SSEffectsDownsamplePushConstant { + float pixel_size[2]; + float z_far; + float z_near; + uint32_t orthogonal; + float radius_sq; + uint32_t pad[2]; + }; + + enum SSEffectsMode { + SS_EFFECTS_DOWNSAMPLE, + SS_EFFECTS_DOWNSAMPLE_HALF_RES, + SS_EFFECTS_DOWNSAMPLE_MIPMAP, + SS_EFFECTS_DOWNSAMPLE_MIPMAP_HALF_RES, + SS_EFFECTS_DOWNSAMPLE_HALF, + SS_EFFECTS_DOWNSAMPLE_HALF_RES_HALF, + SS_EFFECTS_DOWNSAMPLE_FULL_MIPS, + SS_EFFECTS_MAX + }; + + struct SSEffectsGatherConstants { + float rotation_matrices[80]; //5 vec4s * 4 + }; + + struct SSEffects { + SSEffectsDownsamplePushConstant downsample_push_constant; + SsEffectsDownsampleShaderRD downsample_shader; + RID downsample_shader_version; + RID downsample_uniform_set; + bool used_half_size_last_frame = false; + bool used_mips_last_frame = false; + bool used_full_mips_last_frame = false; + + RID gather_constants_buffer; + + RID mirror_sampler; + + RID pipelines[SS_EFFECTS_MAX]; + } ss_effects; + enum SSAOMode { - SSAO_DOWNSAMPLE, - SSAO_DOWNSAMPLE_HALF_RES, - SSAO_DOWNSAMPLE_MIPMAP, - SSAO_DOWNSAMPLE_MIPMAP_HALF_RES, - SSAO_DOWNSAMPLE_HALF, - SSAO_DOWNSAMPLE_HALF_RES_HALF, SSAO_GATHER, SSAO_GATHER_BASE, SSAO_GATHER_ADAPTIVE, @@ -421,15 +459,6 @@ private: SSAO_MAX }; - struct SSAODownsamplePushConstant { - float pixel_size[2]; - float z_far; - float z_near; - uint32_t orthogonal; - float radius_sq; - uint32_t pad[2]; - }; - struct SSAOGatherPushConstant { int32_t screen_size[2]; int pass; @@ -455,7 +484,7 @@ private: float horizon_angle_threshold; float inv_radius_near_limit; - bool is_orthogonal; + uint32_t is_orthogonal; float neg_inv_radius; float load_counter_avg_div; float adaptive_sample_limit; @@ -464,10 +493,6 @@ private: float pass_uv_offset[2]; }; - struct SSAOGatherConstants { - float rotation_matrices[80]; //5 vec4s * 4 - }; - struct SSAOImportanceMapPushConstant { float half_screen_pixel_size[2]; float intensity; @@ -487,15 +512,9 @@ private: }; struct SSAO { - SSAODownsamplePushConstant downsample_push_constant; - SsaoDownsampleShaderRD downsample_shader; - RID downsample_shader_version; - SSAOGatherPushConstant gather_push_constant; SsaoShaderRD gather_shader; RID gather_shader_version; - RID gather_constants_buffer; - bool gather_initialized = false; SSAOImportanceMapPushConstant importance_map_push_constant; SsaoImportanceMapShaderRD importance_map_shader; @@ -511,10 +530,104 @@ private: SsaoInterleaveShaderRD interleave_shader; RID interleave_shader_version; - RID mirror_sampler; RID pipelines[SSAO_MAX]; } ssao; + enum SSILMode { + SSIL_GATHER, + SSIL_GATHER_BASE, + SSIL_GATHER_ADAPTIVE, + SSIL_GENERATE_IMPORTANCE_MAP, + SSIL_PROCESS_IMPORTANCE_MAPA, + SSIL_PROCESS_IMPORTANCE_MAPB, + SSIL_BLUR_PASS, + SSIL_BLUR_PASS_SMART, + SSIL_BLUR_PASS_WIDE, + SSIL_INTERLEAVE, + SSIL_INTERLEAVE_SMART, + SSIL_INTERLEAVE_HALF, + SSIL_MAX + }; + + struct SSILGatherPushConstant { + int32_t screen_size[2]; + int pass; + int quality; + + float half_screen_pixel_size[2]; + float half_screen_pixel_size_x025[2]; + + float NDC_to_view_mul[2]; + float NDC_to_view_add[2]; + + float pad2[2]; + float z_near; + float z_far; + + float radius; + float intensity; + int size_multiplier; + int pad; + + float fade_out_mul; + float fade_out_add; + float normal_rejection_amount; + float inv_radius_near_limit; + + uint32_t is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + int32_t pass_coord_offset[2]; + float pass_uv_offset[2]; + }; + + struct SSILImportanceMapPushConstant { + float half_screen_pixel_size[2]; + float intensity; + float pad; + }; + + struct SSILBlurPushConstant { + float edge_sharpness; + float pad; + float half_screen_pixel_size[2]; + }; + + struct SSILInterleavePushConstant { + float inv_sharpness; + uint32_t size_modifier; + float pixel_size[2]; + }; + + struct SSILProjectionUniforms { + float inv_last_frame_projection_matrix[16]; + }; + + struct SSIL { + SSILGatherPushConstant gather_push_constant; + SsilShaderRD gather_shader; + RID gather_shader_version; + RID projection_uniform_buffer; + + SSILImportanceMapPushConstant importance_map_push_constant; + SsilImportanceMapShaderRD importance_map_shader; + RID importance_map_shader_version; + RID importance_map_load_counter; + RID counter_uniform_set; + + SSILBlurPushConstant blur_push_constant; + SsilBlurShaderRD blur_shader; + RID blur_shader_version; + + SSILInterleavePushConstant interleave_push_constant; + SsilInterleaveShaderRD interleave_shader; + RID interleave_shader_version; + + RID pipelines[SSIL_MAX]; + } ssil; + struct RoughnessLimiterPushConstant { int32_t screen_size[2]; float curve; @@ -615,6 +728,7 @@ private: uint8_t metallic_mask[4]; float projection[16]; + float prev_projection[16]; }; struct ScreenSpaceReflection { @@ -879,11 +993,34 @@ public: Size2i quarter_screen_size = Size2i(); }; + struct SSILSettings { + float radius = 1.0; + float intensity = 2.0; + float sharpness = 0.98; + float normal_rejection = 1.0; + + RS::EnvironmentSSILQuality quality = RS::ENV_SSIL_QUALITY_MEDIUM; + bool half_size = true; + float adaptive_target = 0.5; + int blur_passes = 4; + float fadeout_from = 50.0; + float fadeout_to = 300.0; + + Size2i full_screen_size = Size2i(); + Size2i half_screen_size = Size2i(); + Size2i quarter_screen_size = Size2i(); + }; + void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings); + void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection); + void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set); - void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set); + void generate_ssao(RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set); + + void gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set); + void screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set); void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 03ce2690bf..aaf041ad5a 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -730,7 +730,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.ambient_light_color_energy[3] = 1.0; scene_state.ubo.use_ambient_cubemap = false; scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; + scene_state.ubo.ss_effects_flags = 0; } else if (is_environment(p_render_data->environment)) { RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment); @@ -775,9 +775,14 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.use_reflection_cubemap = false; } - scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_is_ssao_enabled(p_render_data->environment); scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment); scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment); + uint32_t ss_flags = 0; + if (p_opaque_render_buffers) { + ss_flags |= environment_is_ssao_enabled(p_render_data->environment) ? 1 : 0; + ss_flags |= environment_is_ssil_enabled(p_render_data->environment) ? 2 : 0; + } + scene_state.ubo.ss_effects_flags = ss_flags; scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment); scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); @@ -809,7 +814,7 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.use_ambient_cubemap = false; scene_state.ubo.use_reflection_cubemap = false; - scene_state.ubo.ssao_enabled = false; + scene_state.ubo.ss_effects_flags = 0; } scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active(); @@ -1225,6 +1230,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool using_sdfgi = false; bool using_voxelgi = false; bool reverse_cull = false; + bool using_ssil = p_render_data->environment.is_valid() && environment_is_ssil_enabled(p_render_data->environment); if (render_buffer) { screen_size.x = render_buffer->width; @@ -1254,7 +1260,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co opaque_specular_framebuffer = render_buffer->color_specular_fb; } - } else if (p_render_data->environment.is_valid() && (environment_is_ssao_enabled(p_render_data->environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { + } else if (p_render_data->environment.is_valid() && (environment_is_ssao_enabled(p_render_data->environment) || using_ssil || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) { depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } @@ -1449,7 +1455,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co continue_depth = !finish_depth; } - _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID()); + _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID()); RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); @@ -1594,6 +1600,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); + RENDER_TIMESTAMP("Resolve"); + RD::get_singleton()->draw_command_begin_label("Resolve"); if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -1602,6 +1610,13 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_command_begin_label("Copy framebuffer for SSIL"); + if (using_ssil) { + RENDER_TIMESTAMP("Copy Final Framebuffer"); + _copy_framebuffer_to_ssil(p_render_data->render_buffers); + } + RD::get_singleton()->draw_command_end_label(); + if (p_render_data->render_buffers.is_valid()) { _debug_draw_cluster(p_render_data->render_buffers); @@ -2372,6 +2387,15 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend u.ids.push_back(vfog); uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 19; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + RID ssil = rb ? render_buffers_get_ssil_texture(p_render_data->render_buffers) : RID(); + RID texture = ssil.is_valid() ? ssil : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + u.ids.push_back(texture); + uniforms.push_back(u); + } } if (p_index >= (int)render_pass_uniform_sets.size()) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index d6ab4d1db2..b2309996a7 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -251,7 +251,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { float z_far; float z_near; - uint32_t ssao_enabled; + uint32_t ss_effects_flags; float ssao_light_affect; float ssao_ao_affect; uint32_t roughness_limiter_enabled; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 768bd1de9d..0cdcbc952d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,7 +44,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { uniforms.clear(); uses_screen_texture = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index f2a55939f4..98448ce846 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 445623fb86..fc2bc1cadf 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -669,7 +669,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers } - _pre_opaque_render(p_render_data, false, false, RID(), RID()); + _pre_opaque_render(p_render_data, false, false, false, RID(), RID()); uint32_t spec_constant_base_flags = 0; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 485d08b589..0ef1fe6ceb 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index e6d9a60f94..9b96cc18bc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -47,7 +47,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { uniforms.clear(); uses_screen_texture = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 392fac1e3e..770f9bde3b 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index 0d60052666..e812a48d3d 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index e52f47fa47..8d82480b38 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index d013099cce..704a164a3a 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1953,7 +1953,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { uses_sdf = false; uses_time = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 26ccbd3bf5..c9544a5239 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 522a8e8112..2f8ef696cd 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -240,7 +240,7 @@ RendererCompositorRD *RendererCompositorRD::singleton = nullptr; RendererCompositorRD::RendererCompositorRD() { { String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path(); - if (shader_cache_dir == String()) { + if (shader_cache_dir.is_empty()) { shader_cache_dir = "user://"; } DirAccessRef da = DirAccess::open(shader_cache_dir); @@ -261,7 +261,7 @@ RendererCompositorRD::RendererCompositorRD() { shader_cache_dir = String(); //disable only if not editor } - if (shader_cache_dir != String()) { + if (!shader_cache_dir.is_empty()) { bool compress = GLOBAL_GET("rendering/shader_compiler/shader_cache/compress"); bool use_zstd = GLOBAL_GET("rendering/shader_compiler/shader_cache/use_zstd_compression"); bool strip_debug = GLOBAL_GET("rendering/shader_compiler/shader_cache/strip_debug"); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index f69e40e0ff..9a992d5819 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp index 550e59ba98..7ea117ef33 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h index ec9cb4a798..9e36a61870 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -123,6 +123,14 @@ public: float ssr_fade_out = 2.0; float ssr_depth_tolerance = 0.2; + /// SSIL + /// + bool ssil_enabled = false; + float ssil_radius = 5.0; + float ssil_intensity = 1.0; + float ssil_sharpness = 0.98; + float ssil_normal_rejection = 1.0; + /// SDFGI bool sdfgi_enabled = false; RS::EnvironmentSDFGICascades sdfgi_cascades; diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index b6b5c90b39..60e2b237db 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1305,7 +1305,6 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr RD::get_singleton()->draw_list_draw(p_draw_list, false, total_probes, total_points); if (gi->sdfgi_debug_probe_dir != Vector3()) { - print_line("CLICK DEBUG ME?"); uint32_t cascade = 0; Vector3 offset = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascades[cascade].position)) * cascades[cascade].cell_size * Vector3(1.0, 1.0 / y_mult, 1.0); Vector3 probe_size = cascades[cascade].cell_size * (cascade_size / SDFGI::PROBE_DIVISOR) * Vector3(1.0, 1.0 / y_mult, 1.0); @@ -1333,11 +1332,6 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr } } - if (gi->sdfgi_debug_probe_enabled) { - print_line("found: " + gi->sdfgi_debug_probe_index); - } else { - print_line("no found"); - } gi->sdfgi_debug_probe_dir = Vector3(); } @@ -1864,7 +1858,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, Ref<Image> img; img.instantiate(); for (uint32_t i = 0; i < cascade_size; i++) { - Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1); + Vector<uint8_t> subarr = data.slice(128 * 128 * i, 128 * 128 * (i + 1)); img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr); img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png"); } @@ -1877,7 +1871,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, Ref<Image> img; img.instantiate(); for (uint32_t i = 0; i < cascade_size; i++) { - Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1); + Vector<uint8_t> subarr = data.slice(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2); img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr); img->convert(Image::FORMAT_RGBA8); img->save_png("res://cascade_" + itos(cascade) + "_" + itos(i) + ".png"); @@ -2065,7 +2059,7 @@ void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, c for (int i = 0; i < levels.size(); i++) { VoxelGIInstance::Mipmap mipmap; - mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D); + mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, 1, RD::TEXTURE_SLICE_3D); mipmap.level = levels.size() - i - 1; mipmap.cell_offset = 0; for (uint32_t j = 0; j < mipmap.level; j++) { diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index 9f6fc8a9b7..a407199d0a 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -602,19 +602,15 @@ public: }; struct VoxelGIData { - float xform[16]; - float bounds[3]; - float dynamic_range; + float xform[16]; // 64 - 64 - float bias; - float normal_bias; - uint32_t blend_ambient; - uint32_t texture_slot; + float bounds[3]; // 12 - 76 + float dynamic_range; // 4 - 80 - uint32_t pad0; - uint32_t pad1; - uint32_t pad2; - uint32_t mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + uint32_t blend_ambient; // 4 - 92 + uint32_t mipmaps; // 4 - 96 }; struct PushConstant { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index ae8d91a73b..1297f49724 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -427,6 +427,26 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual ssao_fadeout_to = p_fadeout_to; } +void RendererSceneRenderRD::environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) { + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); + ERR_FAIL_COND(!env); + + env->ssil_enabled = p_enable; + env->ssil_radius = p_radius; + env->ssil_intensity = p_intensity; + env->ssil_sharpness = p_sharpness; + env->ssil_normal_rejection = p_normal_rejection; +} + +void RendererSceneRenderRD::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { + ssil_quality = p_quality; + ssil_half_size = p_half_size; + ssil_adaptive_target = p_adaptive_target; + ssil_blur_passes = p_blur_passes; + ssil_fadeout_from = p_fadeout_from; + ssil_fadeout_to = p_fadeout_to; +} + bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); @@ -445,6 +465,12 @@ float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const return env->ssao_direct_light_affect; } +bool RendererSceneRenderRD::environment_is_ssil_enabled(RID p_env) const { + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); + ERR_FAIL_COND_V(!env, false); + return env->ssil_enabled; +} + bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const { RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); @@ -1798,24 +1824,51 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->luminance.current = RID(); } - if (rb->ssao.depth.is_valid()) { - RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao_deinterleaved); - RD::get_singleton()->free(rb->ssao.ao_pong); - RD::get_singleton()->free(rb->ssao.ao_final); + if (rb->ss_effects.linear_depth.is_valid()) { + RD::get_singleton()->free(rb->ss_effects.linear_depth); + rb->ss_effects.linear_depth = RID(); + rb->ss_effects.linear_depth_slices.clear(); + } + + if (rb->ss_effects.ssao.ao_final.is_valid()) { + RD::get_singleton()->free(rb->ss_effects.ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_pong); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_final); + + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[1]); + + rb->ss_effects.ssao.ao_deinterleaved = RID(); + rb->ss_effects.ssao.ao_pong = RID(); + rb->ss_effects.ssao.ao_final = RID(); + rb->ss_effects.ssao.importance_map[0] = RID(); + rb->ss_effects.ssao.importance_map[1] = RID(); + + rb->ss_effects.ssao.ao_deinterleaved_slices.clear(); + rb->ss_effects.ssao.ao_pong_slices.clear(); + } + + if (rb->ss_effects.ssil.ssil_final.is_valid()) { + RD::get_singleton()->free(rb->ss_effects.ssil.ssil_final); + RD::get_singleton()->free(rb->ss_effects.ssil.deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssil.pong); + RD::get_singleton()->free(rb->ss_effects.ssil.edges); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[1]); - RD::get_singleton()->free(rb->ssao.importance_map[0]); - RD::get_singleton()->free(rb->ssao.importance_map[1]); + rb->ss_effects.ssil.ssil_final = RID(); + rb->ss_effects.ssil.deinterleaved = RID(); + rb->ss_effects.ssil.pong = RID(); + rb->ss_effects.ssil.edges = RID(); + rb->ss_effects.ssil.deinterleaved_slices.clear(); + rb->ss_effects.ssil.pong_slices.clear(); + rb->ss_effects.ssil.edges_slices.clear(); + rb->ss_effects.ssil.importance_map[0] = RID(); + rb->ss_effects.ssil.importance_map[1] = RID(); - rb->ssao.depth = RID(); - rb->ssao.ao_deinterleaved = RID(); - rb->ssao.ao_pong = RID(); - rb->ssao.ao_final = RID(); - rb->ssao.importance_map[0] = RID(); - rb->ssao.importance_map[1] = RID(); - rb->ssao.depth_slices.clear(); - rb->ssao.ao_deinterleaved_slices.clear(); - rb->ssao.ao_pong_slices.clear(); + RD::get_singleton()->free(rb->ss_effects.last_frame); + rb->ss_effects.last_frame = RID(); + rb->ss_effects.last_frame_slices.clear(); } if (rb->ssr.blur_radius[0].is_valid()) { @@ -1919,24 +1972,21 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen RENDER_TIMESTAMP("Process SSAO"); - if (rb->ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) { - RD::get_singleton()->free(rb->ssao.depth); - RD::get_singleton()->free(rb->ssao.ao_deinterleaved); - RD::get_singleton()->free(rb->ssao.ao_pong); - RD::get_singleton()->free(rb->ssao.ao_final); + if (rb->ss_effects.ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) { + RD::get_singleton()->free(rb->ss_effects.ssao.ao_deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_pong); + RD::get_singleton()->free(rb->ss_effects.ssao.ao_final); - RD::get_singleton()->free(rb->ssao.importance_map[0]); - RD::get_singleton()->free(rb->ssao.importance_map[1]); + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[1]); - rb->ssao.depth = RID(); - rb->ssao.ao_deinterleaved = RID(); - rb->ssao.ao_pong = RID(); - rb->ssao.ao_final = RID(); - rb->ssao.importance_map[0] = RID(); - rb->ssao.importance_map[1] = RID(); - rb->ssao.depth_slices.clear(); - rb->ssao.ao_deinterleaved_slices.clear(); - rb->ssao.ao_pong_slices.clear(); + rb->ss_effects.ssao.ao_deinterleaved = RID(); + rb->ss_effects.ssao.ao_pong = RID(); + rb->ss_effects.ssao.ao_final = RID(); + rb->ss_effects.ssao.importance_map[0] = RID(); + rb->ss_effects.ssao.importance_map[1] = RID(); + rb->ss_effects.ssao.ao_deinterleaved_slices.clear(); + rb->ss_effects.ssao.ao_pong_slices.clear(); } int buffer_width; @@ -1955,27 +2005,10 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen half_height = (rb->internal_height + 3) / 4; } bool uniform_sets_are_invalid = false; - if (rb->ssao.depth.is_null()) { - //allocate depth slices - + if (rb->ss_effects.ssao.ao_deinterleaved.is_null()) { { - RD::TextureFormat tf; - tf.format = RD::DATA_FORMAT_R16_SFLOAT; - tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; - tf.width = buffer_width; - tf.height = buffer_height; - tf.mipmaps = 4; - tf.array_layers = 4; - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.depth, "SSAO Depth"); - for (uint32_t i = 0; i < tf.mipmaps; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i, RD::TEXTURE_SLICE_2D_ARRAY); - rb->ssao.depth_slices.push_back(slice); - RD::get_singleton()->set_resource_name(rb->ssao.depth_slices[i], "SSAO Depth Mip " + itos(i) + " "); - } + rb->ss_effects.ssao.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, ssao_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); } - { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UNORM; @@ -1984,12 +2017,12 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.height = buffer_height; tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved, "SSAO De-interleaved Array"); + rb->ss_effects.ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_deinterleaved, "SSAO De-interleaved Array"); for (uint32_t i = 0; i < 4; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_deinterleaved, i, 0); - rb->ssao.ao_deinterleaved_slices.push_back(slice); - RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " "); + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssao.ao_deinterleaved, i, 0); + rb->ss_effects.ssao.ao_deinterleaved_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " "); } } @@ -2001,12 +2034,12 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.height = buffer_height; tf.array_layers = 4; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.ao_pong, "SSAO De-interleaved Array Pong"); + rb->ss_effects.ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_pong, "SSAO De-interleaved Array Pong"); for (uint32_t i = 0; i < 4; i++) { - RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.ao_pong, i, 0); - rb->ssao.ao_pong_slices.push_back(slice); - RD::get_singleton()->set_resource_name(rb->ssao.ao_deinterleaved_slices[i], "SSAO De-interleaved Array Layer " + itos(i) + " Pong"); + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssao.ao_pong, i, 0); + rb->ss_effects.ssao.ao_pong_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " Pong"); } } @@ -2016,10 +2049,10 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.width = half_width; tf.height = half_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.importance_map[0], "SSAO Importance Map"); - rb->ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.importance_map[1], "SSAO Importance Map Pong"); + rb->ss_effects.ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.importance_map[0], "SSAO Importance Map"); + rb->ss_effects.ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.importance_map[1], "SSAO Importance Map Pong"); } { RD::TextureFormat tf; @@ -2027,8 +2060,8 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen tf.width = rb->internal_width; tf.height = rb->internal_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; - rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); - RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final"); + rb->ss_effects.ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_final, "SSAO Final"); } ssao_using_half_size = ssao_half_size; uniform_sets_are_invalid = true; @@ -2052,7 +2085,187 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen settings.half_screen_size = Size2i(buffer_width, buffer_height); settings.quarter_screen_size = Size2i(half_width, half_height); - storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set); + storage->get_effects()->generate_ssao(p_normal_buffer, rb->ss_effects.ssao.depth_texture_view, rb->ss_effects.ssao.ao_deinterleaved, rb->ss_effects.ssao.ao_deinterleaved_slices, rb->ss_effects.ssao.ao_pong, rb->ss_effects.ssao.ao_pong_slices, rb->ss_effects.ssao.ao_final, rb->ss_effects.ssao.importance_map[0], rb->ss_effects.ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ss_effects.ssao.gather_uniform_set, rb->ss_effects.ssao.importance_map_uniform_set); +} + +void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection, const Transform3D &p_transform) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND(!rb); + + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment); + ERR_FAIL_COND(!env); + + RENDER_TIMESTAMP("Process SSIL"); + + if (rb->ss_effects.ssil.ssil_final.is_valid() && ssil_using_half_size != ssil_half_size) { + RD::get_singleton()->free(rb->ss_effects.ssil.ssil_final); + RD::get_singleton()->free(rb->ss_effects.ssil.deinterleaved); + RD::get_singleton()->free(rb->ss_effects.ssil.pong); + RD::get_singleton()->free(rb->ss_effects.ssil.edges); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[0]); + RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[1]); + + rb->ss_effects.ssil.ssil_final = RID(); + rb->ss_effects.ssil.deinterleaved = RID(); + rb->ss_effects.ssil.pong = RID(); + rb->ss_effects.ssil.edges = RID(); + rb->ss_effects.ssil.deinterleaved_slices.clear(); + rb->ss_effects.ssil.pong_slices.clear(); + rb->ss_effects.ssil.edges_slices.clear(); + rb->ss_effects.ssil.importance_map[0] = RID(); + rb->ss_effects.ssil.importance_map[1] = RID(); + } + + int buffer_width; + int buffer_height; + int half_width; + int half_height; + if (ssil_half_size) { + buffer_width = (rb->width + 3) / 4; + buffer_height = (rb->height + 3) / 4; + half_width = (rb->width + 7) / 8; + half_height = (rb->height + 7) / 8; + } else { + buffer_width = (rb->width + 1) / 2; + buffer_height = (rb->height + 1) / 2; + half_width = (rb->width + 3) / 4; + half_height = (rb->height + 3) / 4; + } + bool uniform_sets_are_invalid = false; + if (rb->ss_effects.ssil.ssil_final.is_null()) { + { + rb->ss_effects.ssil.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, ssil_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY); + } + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.width = rb->width; + tf.height = rb->height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + rb->ss_effects.ssil.ssil_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.ssil_final, "SSIL texture"); + RD::get_singleton()->texture_clear(rb->ss_effects.ssil.ssil_final, Color(0, 0, 0, 0), 0, 1, 0, 1); + if (rb->ss_effects.last_frame.is_null()) { + tf.mipmaps = 6; + rb->ss_effects.last_frame = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.last_frame, "Last Frame Radiance"); + RD::get_singleton()->texture_clear(rb->ss_effects.last_frame, Color(0, 0, 0, 0), 0, tf.mipmaps, 0, 1); + for (uint32_t i = 0; i < 6; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.last_frame, 0, i); + rb->ss_effects.last_frame_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "Last Frame Radiance Mip " + itos(i) + " "); + } + } + } + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.deinterleaved, "SSIL deinterleaved buffer"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.deinterleaved, i, 0); + rb->ss_effects.ssil.deinterleaved_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer array " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.pong = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.pong, "SSIL deinterleaved pong buffer"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.pong, i, 0); + rb->ss_effects.ssil.pong_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer pong array " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = buffer_width; + tf.height = buffer_height; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.edges = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.edges, "SSIL edges buffer"); + for (uint32_t i = 0; i < 4; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.edges, i, 0); + rb->ss_effects.ssil.edges_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SSIL edges buffer slice " + itos(i) + " "); + } + } + + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = half_width; + tf.height = half_height; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.ssil.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.importance_map[0], "SSIL Importance Map"); + rb->ss_effects.ssil.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.importance_map[1], "SSIL Importance Map Pong"); + } + uniform_sets_are_invalid = true; + ssil_using_half_size = ssil_half_size; + } + + EffectsRD::SSILSettings settings; + settings.radius = env->ssil_radius; + settings.intensity = env->ssil_intensity; + settings.sharpness = env->ssil_sharpness; + settings.normal_rejection = env->ssil_normal_rejection; + + settings.quality = ssil_quality; + settings.half_size = ssil_half_size; + settings.adaptive_target = ssil_adaptive_target; + settings.blur_passes = ssil_blur_passes; + settings.fadeout_from = ssil_fadeout_from; + settings.fadeout_to = ssil_fadeout_to; + settings.full_screen_size = Size2i(rb->width, rb->height); + settings.half_screen_size = Size2i(buffer_width, buffer_height); + settings.quarter_screen_size = Size2i(half_width, half_height); + + CameraMatrix correction; + correction.set_depth_correction(true); + CameraMatrix projection = correction * p_projection; + Transform3D transform = p_transform; + transform.set_origin(Vector3(0.0, 0.0, 0.0)); + CameraMatrix last_frame_projection = rb->ss_effects.last_frame_projection * CameraMatrix(rb->ss_effects.last_frame_transform.affine_inverse()) * CameraMatrix(transform) * projection.inverse(); + + storage->get_effects()->screen_space_indirect_lighting(rb->ss_effects.last_frame, rb->ss_effects.ssil.ssil_final, p_normal_buffer, rb->ss_effects.ssil.depth_texture_view, rb->ss_effects.ssil.deinterleaved, rb->ss_effects.ssil.deinterleaved_slices, rb->ss_effects.ssil.pong, rb->ss_effects.ssil.pong_slices, rb->ss_effects.ssil.importance_map[0], rb->ss_effects.ssil.importance_map[1], rb->ss_effects.ssil.edges, rb->ss_effects.ssil.edges_slices, p_projection, last_frame_projection, settings, uniform_sets_are_invalid, rb->ss_effects.ssil.gather_uniform_set, rb->ss_effects.ssil.importance_map_uniform_set, rb->ss_effects.ssil.projection_uniform_set); + rb->ss_effects.last_frame_projection = projection; + rb->ss_effects.last_frame_transform = transform; +} + +void RendererSceneRenderRD::_copy_framebuffer_to_ssil(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND(!rb); + + if (rb->ss_effects.last_frame.is_valid()) { + storage->get_effects()->copy_to_rect(rb->texture, rb->ss_effects.last_frame, Rect2i(0, 0, rb->width, rb->height)); + + int width = rb->width; + int height = rb->height; + for (int i = 0; i < rb->ss_effects.last_frame_slices.size() - 1; i++) { + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + storage->get_effects()->make_mipmap(rb->ss_effects.last_frame_slices[i], rb->ss_effects.last_frame_slices[i + 1], Size2i(width, height)); + } + } } void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) { @@ -2427,10 +2640,14 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID } } - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao_final.is_valid()) { + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ss_effects.ssao.ao_final.is_valid()) { + Size2 rtsize = storage->render_target_get_size(rb->render_target); + effects->copy_to_fb_rect(rb->ss_effects.ssao.ao_final, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + } + + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb->ss_effects.ssil.ssil_final.is_valid()) { Size2 rtsize = storage->render_target_get_size(rb->render_target); - RID ao_buf = rb->ssao.ao_final; - effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true); + effects->copy_to_fb_rect(rb->ss_effects.ssil.ssil_final, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false); } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) { @@ -2494,7 +2711,13 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); - return rb->ssao.ao_final; + return rb->ss_effects.ssao.ao_final; +} +RID RendererSceneRenderRD::render_buffers_get_ssil_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + + return rb->ss_effects.ssil.ssil_final; } RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) { @@ -3581,7 +3804,7 @@ void RendererSceneRenderRD::FogShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } @@ -4417,9 +4640,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e uint32_t cluster_screen_width = (rb->width - 1) / cluster_size + 1; uint32_t cluster_screen_height = (rb->height - 1) / cluster_size + 1; - params.cluster_type_size = cluster_screen_width * cluster_screen_height * (32 + 32); - params.cluster_width = cluster_screen_width; params.max_cluster_element_count_div_32 = max_cluster_elements / 32; + params.cluster_type_size = cluster_screen_width * cluster_screen_height * (params.max_cluster_element_count_div_32 + 32); + params.cluster_width = cluster_screen_width; params.screen_size[0] = rb->width; params.screen_size[1] = rb->height; @@ -4528,7 +4751,7 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo } } -void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) { +void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) { // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time if (p_render_data->render_buffers.is_valid() && p_use_gi) { @@ -4615,9 +4838,40 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } if (p_render_data->render_buffers.is_valid()) { + if (p_use_ssao || p_use_ssil) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); + ERR_FAIL_COND(!rb); + + bool invalidate_uniform_set = false; + if (rb->ss_effects.linear_depth.is_null()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R16_SFLOAT; + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + tf.width = (rb->width + 1) / 2; + tf.height = (rb->height + 1) / 2; + tf.mipmaps = 5; + tf.array_layers = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; + rb->ss_effects.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->ss_effects.linear_depth, "SS Effects Depth"); + for (uint32_t i = 0; i < tf.mipmaps; i++) { + RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY); + rb->ss_effects.linear_depth_slices.push_back(slice); + RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " "); + } + invalidate_uniform_set = true; + } + + storage->get_effects()->downsample_depth(rb->depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, Size2i(rb->width, rb->height), p_render_data->cam_projection); + } + if (p_use_ssao) { _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_buffer, p_render_data->cam_projection); } + + if (p_use_ssil) { + _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_buffer, p_render_data->cam_projection, p_render_data->cam_transform); + } } //full barrier here, we need raster, transfer and compute and it depends from the previous work @@ -5499,6 +5753,9 @@ void fog() { sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality"))); sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale"); sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale"); + + environment_set_ssil_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to")); + directional_penumbra_shadow_kernel = memnew_arr(float, 128); directional_soft_shadow_kernel = memnew_arr(float, 128); penumbra_shadow_kernel = memnew_arr(float, 128); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 98ab1a2c3c..55891bc2a9 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -129,12 +129,15 @@ protected: void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera); + void _process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection, const Transform3D &p_transform); + void _copy_framebuffer_to_ssil(RID p_render_buffers); + void _ensure_ss_effects(RID p_render_buffers, bool p_using_ssil); bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi); - void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); + void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data); void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data); @@ -415,6 +418,14 @@ private: float ssao_fadeout_from = 50.0; float ssao_fadeout_to = 300.0; + RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM; + bool ssil_half_size = false; + bool ssil_using_half_size = false; + float ssil_adaptive_target = 0.5; + int ssil_blur_passes = 4; + float ssil_fadeout_from = 50.0; + float ssil_fadeout_to = 300.0; + bool glow_bicubic_upscale = false; bool glow_high_quality = false; RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW; @@ -524,20 +535,47 @@ private: RID current_fb; } luminance; - struct SSAO { - RID depth; - Vector<RID> depth_slices; - RID ao_deinterleaved; - Vector<RID> ao_deinterleaved_slices; - RID ao_pong; - Vector<RID> ao_pong_slices; - RID ao_final; - RID importance_map[2]; + struct SSEffects { + RID linear_depth; + Vector<RID> linear_depth_slices; RID downsample_uniform_set; - RID gather_uniform_set; - RID importance_map_uniform_set; - } ssao; + + RID last_frame; + Vector<RID> last_frame_slices; + + CameraMatrix last_frame_projection; + Transform3D last_frame_transform; + + struct SSAO { + RID ao_deinterleaved; + Vector<RID> ao_deinterleaved_slices; + RID ao_pong; + Vector<RID> ao_pong_slices; + RID ao_final; + RID importance_map[2]; + RID depth_texture_view; + + RID gather_uniform_set; + RID importance_map_uniform_set; + } ssao; + + struct SSIL { + RID ssil_final; + RID deinterleaved; + Vector<RID> deinterleaved_slices; + RID pong; + Vector<RID> pong_slices; + RID edges; + Vector<RID> edges_slices; + RID importance_map[2]; + RID depth_texture_view; + + RID gather_uniform_set; + RID importance_map_uniform_set; + RID projection_uniform_set; + } ssil; + } ss_effects; struct SSR { RID normal_scaled; @@ -1046,9 +1084,12 @@ public: virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) override; virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override; virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) override; + virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; bool environment_is_ssao_enabled(RID p_env) const; float environment_get_ssao_ao_affect(RID p_env) const; float environment_get_ssao_light_affect(RID p_env) const; + bool environment_is_ssil_enabled(RID p_env) const; bool environment_is_ssr_enabled(RID p_env) const; bool environment_is_sdfgi_enabled(RID p_env) const; @@ -1344,6 +1385,7 @@ public: RID render_buffers_get_depth_texture(RID p_render_buffers); RID render_buffers_get_ao_texture(RID p_render_buffers); + RID render_buffers_get_ssil_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); RID render_buffers_get_back_depth_texture(RID p_render_buffers); RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index a9c39fb937..8fb3c607fa 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -46,7 +46,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { ubo_size = 0; uniforms.clear(); - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } @@ -360,7 +360,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); } - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, RD::TEXTURE_SLICE_CUBEMAP); + layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer + i * 6, j, 1, RD::TEXTURE_SLICE_CUBEMAP); mmw = MAX(1, mmw >> 1); mmh = MAX(1, mmh >> 1); @@ -388,7 +388,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex); } - layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, RD::TEXTURE_SLICE_CUBEMAP); + layer.views.write[j] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, j, 1, RD::TEXTURE_SLICE_CUBEMAP); mmw = MAX(1, mmw >> 1); mmh = MAX(1, mmh >> 1); @@ -397,7 +397,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR layers.push_back(layer); } - radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP); + radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, 1, RD::TEXTURE_SLICE_CUBEMAP); RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap"); RD::TextureFormat tf; tf.format = p_texture_format; @@ -418,7 +418,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR ReflectionData::DownsampleLayer::Mipmap &mm = downsampled_layer.mipmaps.write[j]; mm.size.width = mmw; mm.size.height = mmh; - mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP); + mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, 1, RD::TEXTURE_SLICE_CUBEMAP); RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " "); if (prefer_raster_effects) { // we need a framebuffer for each side of our cubemap diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 8689395bea..1359cdec67 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 29e4a63cbb..496dde123d 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1089,7 +1089,7 @@ Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { const Texture::BufferSlice3D &bs = tex->buffer_slices_3d[i]; ERR_FAIL_COND_V(bs.offset >= (uint32_t)all_data.size(), Vector<Ref<Image>>()); ERR_FAIL_COND_V(bs.offset + bs.buffer_size > (uint32_t)all_data.size(), Vector<Ref<Image>>()); - Vector<uint8_t> sub_region = all_data.subarray(bs.offset, bs.offset + bs.buffer_size - 1); + Vector<uint8_t> sub_region = all_data.slice(bs.offset, bs.offset + bs.buffer_size); Ref<Image> img; img.instantiate(); @@ -2655,13 +2655,13 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName uint32_t size = 0U; // The following code enforces a 16-byte alignment of uniform arrays. if (E.value.array_size > 0) { - size = ShaderLanguage::get_type_size(E.value.type) * E.value.array_size; + size = ShaderLanguage::get_datatype_size(E.value.type) * E.value.array_size; int m = (16 * E.value.array_size); if ((size % m) != 0U) { size += m - (size % m); } } else { - size = ShaderLanguage::get_type_size(E.value.type); + size = ShaderLanguage::get_datatype_size(E.value.type); } ERR_CONTINUE(offset + size > p_buffer_size); #endif @@ -2818,11 +2818,14 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: { rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK); } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: { + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + case ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); } break; default: { rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); @@ -2861,7 +2864,7 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari } } #ifdef TOOLS_ENABLED - if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) { roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } #endif @@ -2901,7 +2904,7 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); } #ifdef TOOLS_ENABLED - if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) { roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } #endif @@ -5820,7 +5823,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { uniforms.clear(); uses_collision = false; - if (code == String()) { + if (code.is_empty()) { return; //just invalid, but no error } @@ -9234,7 +9237,7 @@ void RendererStorageRD::_update_global_variables() { for (uint32_t i = 0; i < total_regions; i++) { if (global_variables.buffer_dirty_regions[i]) { - RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, global_variables.buffer_values); + RD::get_singleton()->buffer_update(global_variables.buffer, i * region_byte_size, region_byte_size, &global_variables.buffer_values[i * GlobalVariables::BUFFER_DIRTY_REGION_SIZE]); global_variables.buffer_dirty_regions[i] = false; } @@ -9265,7 +9268,6 @@ void RendererStorageRD::_update_global_variables() { ERR_CONTINUE(!material); //wtf _material_queue_update(material, false, true); - print_line("update material texture?"); } global_variables.must_update_texture_materials = false; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 9a64480c3e..8f044dbe75 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 77d3a2e766..38ac00176f 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -54,81 +54,6 @@ static String _typestr(SL::DataType p_type) { return type; } -static int _get_datatype_size(SL::DataType p_type) { - switch (p_type) { - case SL::TYPE_VOID: - return 0; - case SL::TYPE_BOOL: - return 4; - case SL::TYPE_BVEC2: - return 8; - case SL::TYPE_BVEC3: - return 12; - case SL::TYPE_BVEC4: - return 16; - case SL::TYPE_INT: - return 4; - case SL::TYPE_IVEC2: - return 8; - case SL::TYPE_IVEC3: - return 12; - case SL::TYPE_IVEC4: - return 16; - case SL::TYPE_UINT: - return 4; - case SL::TYPE_UVEC2: - return 8; - case SL::TYPE_UVEC3: - return 12; - case SL::TYPE_UVEC4: - return 16; - case SL::TYPE_FLOAT: - return 4; - case SL::TYPE_VEC2: - return 8; - case SL::TYPE_VEC3: - return 12; - case SL::TYPE_VEC4: - return 16; - case SL::TYPE_MAT2: - return 32; // 4 * 4 + 4 * 4 - case SL::TYPE_MAT3: - return 48; // 4 * 4 + 4 * 4 + 4 * 4 - case SL::TYPE_MAT4: - return 64; - case SL::TYPE_SAMPLER2D: - return 16; - case SL::TYPE_ISAMPLER2D: - return 16; - case SL::TYPE_USAMPLER2D: - return 16; - case SL::TYPE_SAMPLER2DARRAY: - return 16; - case SL::TYPE_ISAMPLER2DARRAY: - return 16; - case SL::TYPE_USAMPLER2DARRAY: - return 16; - case SL::TYPE_SAMPLER3D: - return 16; - case SL::TYPE_ISAMPLER3D: - return 16; - case SL::TYPE_USAMPLER3D: - return 16; - case SL::TYPE_SAMPLERCUBE: - return 16; - case SL::TYPE_SAMPLERCUBEARRAY: - return 16; - case SL::TYPE_STRUCT: - return 0; - - case SL::TYPE_MAX: { - ERR_FAIL_V(0); - }; - } - - ERR_FAIL_V(0); -} - static int _get_datatype_alignment(SL::DataType p_type) { switch (p_type) { case SL::TYPE_VOID: @@ -658,12 +583,12 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_defines.write[uniform.order] = ucode; if (is_buffer_global) { //globals are indices into the global table - uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); + uniform_sizes.write[uniform.order] = ShaderLanguage::get_datatype_size(ShaderLanguage::TYPE_UINT); uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); } else { // The following code enforces a 16-byte alignment of uniform arrays. if (uniform.array_size > 0) { - int size = _get_datatype_size(uniform.type) * uniform.array_size; + int size = ShaderLanguage::get_datatype_size(uniform.type) * uniform.array_size; int m = (16 * uniform.array_size); if ((size % m) != 0) { size += m - (size % m); @@ -671,7 +596,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_sizes.write[uniform.order] = size; uniform_alignments.write[uniform.order] = 16; } else { - uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + uniform_sizes.write[uniform.order] = ShaderLanguage::get_datatype_size(uniform.type); uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type); } } @@ -1318,6 +1243,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge code += ")"; } break; + case SL::OP_EMPTY: { + // Semicolon (or empty statement) - ignored. + } break; default: { if (p_use_scope) { @@ -1410,7 +1338,13 @@ ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName & } Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_variable_type); + SL::ShaderCompileInfo info; + info.functions = ShaderTypes::get_singleton()->get_functions(p_mode); + info.render_modes = ShaderTypes::get_singleton()->get_modes(p_mode); + info.shader_types = ShaderTypes::get_singleton()->get_types(); + info.global_variable_type_func = _get_variable_type; + + Error err = parser.compile(p_code, info); if (err != OK) { Vector<String> shader = p_code.split("\n"); diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 2ab689c27c..5670d881f6 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 2568090918..73766d14d8 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -79,7 +79,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { } if (push_chunk) { - if (text != String()) { + if (!text.is_empty()) { StageTemplate::Chunk text_chunk; text_chunk.type = StageTemplate::Chunk::TYPE_TEXT; text_chunk.text = text.utf8(); @@ -90,7 +90,7 @@ void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) { } } - if (text != String()) { + if (!text.is_empty()) { StageTemplate::Chunk text_chunk; text_chunk.type = StageTemplate::Chunk::TYPE_TEXT; text_chunk.text = text.utf8(); @@ -638,7 +638,7 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String variants_enabled.push_back(true); } - if (shader_cache_dir != String()) { + if (!shader_cache_dir.is_empty()) { StringBuilder hash_build; hash_build.append("[base_hash]"); diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 984b168659..06f78ab193 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl index 4110a95ddb..a89f83b5c4 100644 --- a/servers/rendering/renderer_rd/shaders/copy.glsl +++ b/servers/rendering/renderer_rd/shaders/copy.glsl @@ -84,6 +84,8 @@ void main() { color += texelFetch(source_color, base_pos + ivec2(1, 0), 0); color += texelFetch(source_color, base_pos + ivec2(1, 1), 0); color /= 4.0; + color = mix(color, vec4(100.0, 100.0, 100.0, 1.0), isinf(color)); + color = mix(color, vec4(100.0, 100.0, 100.0, 1.0), isnan(color)); imageStore(dest_buffer, pos + params.target, color); #endif @@ -132,6 +134,13 @@ void main() { local_cache[dest_index + 16] = textureLod(source_color, quad_center_uv + vec2(0.0, 1.0 / params.section.w), 0); local_cache[dest_index + 16 + 1] = textureLod(source_color, quad_center_uv + vec2(1.0 / params.section.zw), 0); } + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { + // Tonemap initial samples to reduce weight of fireflies: https://graphicrants.blogspot.com/2013/12/tone-mapping.html + local_cache[dest_index] /= 1.0 + dot(local_cache[dest_index].rgb, vec3(0.299, 0.587, 0.114)); + local_cache[dest_index + 1] /= 1.0 + dot(local_cache[dest_index + 1].rgb, vec3(0.299, 0.587, 0.114)); + local_cache[dest_index + 16] /= 1.0 + dot(local_cache[dest_index + 16].rgb, vec3(0.299, 0.587, 0.114)); + local_cache[dest_index + 16 + 1] /= 1.0 + dot(local_cache[dest_index + 16 + 1].rgb, vec3(0.299, 0.587, 0.114)); + } memoryBarrierShared(); barrier(); @@ -177,6 +186,11 @@ void main() { color += temp_cache[index - 2] * 0.140367; color += temp_cache[index - 3] * 0.106595; + if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { + // Undo tonemap to restore range: https://graphicrants.blogspot.com/2013/12/tone-mapping.html + color /= 1.0 - dot(color.rgb, vec3(0.299, 0.587, 0.114)); + } + color *= params.glow_strength; if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) { @@ -186,7 +200,7 @@ void main() { #endif color *= params.glow_exposure; - float luminance = max(color.r, max(color.g, color.b)); + float luminance = dot(color.rgb, vec3(0.299, 0.587, 0.114)); float feedback = max(smoothstep(params.glow_hdr_threshold, params.glow_hdr_threshold + params.glow_hdr_scale, luminance), params.glow_bloom); color = min(color * feedback, vec4(params.glow_luminance_cap)); diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl index 4e2ba84033..54a7790f77 100644 --- a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl +++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index 5528ea3659..9854f124d7 100644 --- a/servers/rendering/renderer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -68,19 +68,15 @@ sdfgi; #define MAX_VOXEL_GI_INSTANCES 8 struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; + mat4 xform; // 64 - 64 - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 - uint pad0; - uint pad1; - uint pad2; - uint mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 }; layout(set = 0, binding = 16, std140) uniform VoxelGIs { diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl index 25d87ca45d..a6d65bffeb 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl @@ -7,7 +7,6 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #define NO_CHILDREN 0xFFFFFFFF -#define GREY_VEC vec3(0.33333, 0.33333, 0.33333) struct CellChildren { uint children[8]; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index e4628b2d5a..9b72ccc87d 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -1153,7 +1153,7 @@ void main() { } #endif // !USE_LIGHTMAP - if (scene_data.ssao_enabled) { + if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) { float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r; ao = min(ao, ssao); ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect); @@ -1223,6 +1223,12 @@ void main() { // convert ao to direct light ao ao = mix(1.0, ao, ao_light_affect); + if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) { + vec4 ssil = textureLod(sampler2D(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv, 0.0); + ambient_light *= 1.0 - ssil.a; + ambient_light += ssil.rgb * albedo.rgb; + } + //this saves some VGPRs vec3 f0 = F0(metallic, specular, albedo); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index be29cf4f58..0f7cd18534 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -72,6 +72,9 @@ layout(set = 0, binding = 4) uniform sampler light_projector_sampler; //3 bits of stride #define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF +#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO 1 +#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL 2 + layout(set = 0, binding = 5, std430) restrict readonly buffer OmniLights { LightData data[]; } @@ -201,7 +204,7 @@ layout(set = 1, binding = 0, std140) uniform SceneData { float z_far; float z_near; - bool ssao_enabled; + uint ss_effects_flags; float ssao_light_affect; float ssao_ao_affect; bool roughness_limiter_enabled; @@ -305,19 +308,15 @@ layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; + mat4 xform; // 64 - 64 - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; - uint mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 }; layout(set = 1, binding = 17, std140) uniform VoxelGIs { @@ -327,6 +326,8 @@ voxel_gi_instances; layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; +layout(set = 1, binding = 19) uniform texture2D ssil_buffer; + #endif /* Set 2 Skeleton & Instancing (can change per item) */ diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl index 78e0a85341..fde5688301 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl @@ -223,7 +223,6 @@ void main() { blur_radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h); } } - final_color = imageLoad(source_diffuse, ivec2((final_pos - 0.5) * pixel_size)); imageStore(blur_radius_image, ssC, vec4(blur_radius / 255.0)); //stored in r8 diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl index ee0db6a6f0..bdabc146d8 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl +++ b/servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl @@ -42,6 +42,9 @@ layout(r16f, set = 1, binding = 0) uniform restrict writeonly image2DArray dest_ layout(r16f, set = 2, binding = 0) uniform restrict writeonly image2DArray dest_image1; layout(r16f, set = 2, binding = 1) uniform restrict writeonly image2DArray dest_image2; layout(r16f, set = 2, binding = 2) uniform restrict writeonly image2DArray dest_image3; +#ifdef GENERATE_FULL_MIPS +layout(r16f, set = 2, binding = 3) uniform restrict writeonly image2DArray dest_image4; +#endif #endif vec4 screen_space_to_view_space_depth(vec4 p_depth) { @@ -150,7 +153,27 @@ void prepare_depths_and_mips(vec4 p_samples, uvec2 p_output_coord, uvec2 p_gtid) float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); imageStore(dest_image3, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); +#ifndef GENERATE_FULL_MIPS + } +#else + depth_buffer[depth_array_index][buffer_coord.x][buffer_coord.y] = avg; } + still_alive = p_gtid.x % 16 == depth_array_offset.x && depth_array_offset.y % 16 == depth_array_offset.y; + + p_output_coord /= 2; + groupMemoryBarrier(); + barrier(); + + if (still_alive) { + float sample_00 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 0]; + float sample_01 = depth_buffer[depth_array_index][buffer_coord.x + 0][buffer_coord.y + 8]; + float sample_10 = depth_buffer[depth_array_index][buffer_coord.x + 8][buffer_coord.y + 0]; + float sample_11 = depth_buffer[depth_array_index][buffer_coord.x + 8][buffer_coord.y + 8]; + + float avg = mip_smart_average(vec4(sample_00, sample_01, sample_10, sample_11)); + imageStore(dest_image4, ivec3(p_output_coord.x, p_output_coord.y, depth_array_index), vec4(avg)); + } +#endif } #else #ifndef USE_HALF_BUFFERS diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl index 6e945edfcd..18cab75c3b 100644 --- a/servers/rendering/renderer_rd/shaders/ssao.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao.glsl @@ -23,8 +23,6 @@ #VERSION_DEFINES -#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 - #define INTELSSAO_MAIN_DISK_SAMPLE_COUNT (32) const vec4 sample_pattern[INTELSSAO_MAIN_DISK_SAMPLE_COUNT] = { vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), @@ -62,7 +60,6 @@ const int num_taps[5] = { 3, 5, 12, 0, 0 }; #define SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) #define SSAO_MAX_TAPS 32 -#define SSAO_MAX_REF_TAPS 512 #define SSAO_ADAPTIVE_TAP_BASE_COUNT 5 #define SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSAO_MAX_TAPS - SSAO_ADAPTIVE_TAP_BASE_COUNT) #define SSAO_DEPTH_MIP_LEVELS 4 diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl index d9cd2b4e85..b154f5e527 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl @@ -128,19 +128,19 @@ void main() { #ifdef MODE_NON_SMART - vec2 halfPixel = params.half_screen_pixel_size * 0.5f; + vec2 half_pixel = params.half_screen_pixel_size * 0.5; vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; - vec2 centre = textureLod(source_ssao, vec2(uv), 0.0).xy; + vec2 center = textureLod(source_ssao, vec2(uv), 0.0).xy; vec4 vals; - vals.x = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x * 3, -halfPixel.y)), 0.0).x; - vals.y = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x, -halfPixel.y * 3)), 0.0).x; - vals.z = textureLod(source_ssao, vec2(uv + vec2(-halfPixel.x, +halfPixel.y * 3)), 0.0).x; - vals.w = textureLod(source_ssao, vec2(uv + vec2(+halfPixel.x * 3, +halfPixel.y)), 0.0).x; + vals.x = textureLod(source_ssao, vec2(uv + vec2(-half_pixel.x * 3, -half_pixel.y)), 0.0).x; + vals.y = textureLod(source_ssao, vec2(uv + vec2(+half_pixel.x, -half_pixel.y * 3)), 0.0).x; + vals.z = textureLod(source_ssao, vec2(uv + vec2(-half_pixel.x, +half_pixel.y * 3)), 0.0).x; + vals.w = textureLod(source_ssao, vec2(uv + vec2(+half_pixel.x * 3, +half_pixel.y)), 0.0).x; - vec2 sampled = vec2(dot(vals, vec4(0.2)) + centre.x * 0.2, centre.y); + vec2 sampled = vec2(dot(vals, vec4(0.2)) + center.x * 0.2, center.y); #else #ifdef MODE_SMART diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl index 687fe1e6e2..23eba34d63 100644 --- a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl +++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl @@ -26,7 +26,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; #ifdef GENERATE_MAP -layout(set = 0, binding = 0) uniform sampler2DArray source_ssao; +layout(set = 0, binding = 0) uniform sampler2DArray source_texture; #else layout(set = 0, binding = 0) uniform sampler2D source_importance; #endif @@ -56,11 +56,10 @@ void main() { vec2 base_uv = (vec2(base_position) + vec2(0.5f, 0.5f)) * params.half_screen_pixel_size; - float avg = 0.0; float minV = 1.0; float maxV = 0.0; for (int i = 0; i < 4; i++) { - vec4 vals = textureGather(source_ssao, vec3(base_uv, i)); + vec4 vals = textureGather(source_texture, vec3(base_uv, i)); // apply the same modifications that would have been applied in the main shader vals = params.intensity * vals; @@ -69,8 +68,6 @@ void main() { vals = pow(clamp(vals, 0.0, 1.0), vec4(params.power)); - avg += dot(vec4(vals.x, vals.y, vals.z, vals.w), vec4(1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0, 1.0 / 16.0)); - maxV = max(maxV, max(max(vals.x, vals.y), max(vals.z, vals.w))); minV = min(minV, min(min(vals.x, vals.y), min(vals.z, vals.w))); } diff --git a/servers/rendering/renderer_rd/shaders/ssil.glsl b/servers/rendering/renderer_rd/shaders/ssil.glsl new file mode 100644 index 0000000000..d1f8f42790 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil.glsl @@ -0,0 +1,444 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +// 2021-05-27: clayjohn: convert SSAO to SSIL +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define SSIL_MAIN_DISK_SAMPLE_COUNT (32) +const vec4 sample_pattern[SSIL_MAIN_DISK_SAMPLE_COUNT] = { + vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), + vec4(-0.13570161, -0.64190155, 1.250000, -0.532765), vec4(-0.26193795, -0.08205118, 0.670000, -1.783245), vec4(-0.61177456, 0.66664219, 0.710000, -0.044234), vec4(0.43675563, 0.25119025, 0.610000, -1.167283), + vec4(0.07884444, 0.86618668, 0.640000, -0.459002), vec4(-0.12790935, -0.29869005, 0.600000, -1.729424), vec4(-0.04031125, 0.02413622, 0.600000, -4.792042), vec4(0.16201244, -0.52851415, 0.790000, -1.067055), + vec4(-0.70991218, 0.47301072, 0.640000, -0.335236), vec4(0.03277707, -0.22349690, 0.600000, -1.982384), vec4(0.68921727, 0.36800742, 0.630000, -0.266718), vec4(0.29251814, 0.37775412, 0.610000, -1.422520), + vec4(-0.12224089, 0.96582592, 0.600000, -0.426142), vec4(0.11071457, -0.16131058, 0.600000, -2.165947), vec4(0.46562141, -0.59747696, 0.600000, -0.189760), vec4(-0.51548797, 0.11804193, 0.600000, -1.246800), + vec4(0.89141309, -0.42090443, 0.600000, 0.028192), vec4(-0.32402530, -0.01591529, 0.600000, -1.543018), vec4(0.60771245, 0.41635221, 0.600000, -0.605411), vec4(0.02379565, -0.08239821, 0.600000, -3.809046), + vec4(0.48951152, -0.23657045, 0.600000, -1.189011), vec4(-0.17611565, -0.81696892, 0.600000, -0.513724), vec4(-0.33930185, -0.20732205, 0.600000, -1.698047), vec4(-0.91974425, 0.05403209, 0.600000, 0.062246), + vec4(-0.15064627, -0.14949332, 0.600000, -1.896062), vec4(0.53180975, -0.35210401, 0.600000, -0.758838), vec4(0.41487166, 0.81442589, 0.600000, -0.505648), vec4(-0.24106961, -0.32721516, 0.600000, -1.665244) +}; + +// these values can be changed (up to SSIL_MAX_TAPS) with no changes required elsewhere; values for 4th and 5th preset are ignored but array needed to avoid compilation errors +// the actual number of texture samples is two times this value (each "tap" has two symmetrical depth texture samples) +const int num_taps[5] = { 3, 5, 12, 0, 0 }; + +#define SSIL_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET (99) // to disable simply set to 99 or similar +#define SSIL_TILT_SAMPLES_AMOUNT (0.4) +// +#define SSIL_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET (1) // to disable simply set to 99 or similar +#define SSIL_HALOING_REDUCTION_AMOUNT (0.8) // values from 0.0 - 1.0, 1.0 means max weighting (will cause artifacts, 0.8 is more reasonable) +// +#define SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET (2) +#define SSIL_DEPTH_MIPS_GLOBAL_OFFSET (-4.3) // best noise/quality/performance tradeoff, found empirically +// +// !!warning!! the edge handling is hard-coded to 'disabled' on quality level 0, and enabled above, on the C++ side; while toggling it here will work for +// testing purposes, it will not yield performance gains (or correct results) +#define SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (1) +// +#define SSIL_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) + +#define SSIL_MAX_TAPS 32 +#define SSIL_ADAPTIVE_TAP_BASE_COUNT 5 +#define SSIL_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSIL_MAX_TAPS - SSIL_ADAPTIVE_TAP_BASE_COUNT) +#define SSIL_DEPTH_MIP_LEVELS 4 + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2DArray source_depth_mipmaps; +layout(rgba8, set = 0, binding = 1) uniform restrict readonly image2D source_normal; +layout(set = 0, binding = 2) uniform Constants { //get into a lower set + vec4 rotation_matrices[20]; +} +constants; + +#ifdef ADAPTIVE +layout(rgba16, set = 1, binding = 0) uniform restrict readonly image2DArray source_ssil; +layout(set = 1, binding = 1) uniform sampler2D source_importance; +layout(set = 1, binding = 2, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(rgba16, set = 2, binding = 0) uniform restrict writeonly image2D dest_image; +layout(r8, set = 2, binding = 1) uniform image2D edges_weights_image; + +layout(set = 3, binding = 0) uniform sampler2D last_frame; +layout(set = 3, binding = 1) uniform ProjectionConstants { + mat4 reprojection; +} +projection_constants; + +layout(push_constant, binding = 3, std430) uniform Params { + ivec2 screen_size; + int pass; + int quality; + + vec2 half_screen_pixel_size; + vec2 half_screen_pixel_size_x025; + + vec2 NDC_to_view_mul; + vec2 NDC_to_view_add; + + vec2 pad2; + float z_near; + float z_far; + + float radius; + float intensity; + int size_multiplier; + int pad; + + float fade_out_mul; + float fade_out_add; + float normal_rejection_amount; + float inv_radius_near_limit; + + bool is_orthogonal; + float neg_inv_radius; + float load_counter_avg_div; + float adaptive_sample_limit; + + ivec2 pass_coord_offset; + vec2 pass_uv_offset; +} +params; + +float pack_edges(vec4 p_edgesLRTB) { + p_edgesLRTB = round(clamp(p_edgesLRTB, 0.0, 1.0) * 3.05); + return dot(p_edgesLRTB, vec4(64.0 / 255.0, 16.0 / 255.0, 4.0 / 255.0, 1.0 / 255.0)); +} + +vec3 NDC_to_view_space(vec2 p_pos, float p_viewspace_depth) { + if (params.is_orthogonal) { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add), p_viewspace_depth); + } else { + return vec3((params.NDC_to_view_mul * p_pos.xy + params.NDC_to_view_add) * p_viewspace_depth, p_viewspace_depth); + } +} + +// calculate effect radius and fit our screen sampling pattern inside it +void calculate_radius_parameters(const float p_pix_center_length, const vec2 p_pixel_size_at_center, out float r_lookup_radius, out float r_radius, out float r_fallof_sq) { + r_radius = params.radius; + + // when too close, on-screen sampling disk will grow beyond screen size; limit this to avoid closeup temporal artifacts + const float too_close_limit = clamp(p_pix_center_length * params.inv_radius_near_limit, 0.0, 1.0) * 0.8 + 0.2; + + r_radius *= too_close_limit; + + // 0.85 is to reduce the radius to allow for more samples on a slope to still stay within influence + r_lookup_radius = (0.85 * r_radius) / p_pixel_size_at_center.x; + + // used to calculate falloff (both for AO samples and per-sample weights) + r_fallof_sq = -1.0 / (r_radius * r_radius); +} + +vec4 calculate_edges(const float p_center_z, const float p_left_z, const float p_right_z, const float p_top_z, const float p_bottom_z) { + // slope-sensitive depth-based edge detection + vec4 edgesLRTB = vec4(p_left_z, p_right_z, p_top_z, p_bottom_z) - p_center_z; + vec4 edgesLRTB_slope_adjusted = edgesLRTB + edgesLRTB.yxwz; + edgesLRTB = min(abs(edgesLRTB), abs(edgesLRTB_slope_adjusted)); + return clamp((1.3 - edgesLRTB / (p_center_z * 0.040)), 0.0, 1.0); +} + +vec3 decode_normal(vec3 p_encoded_normal) { + vec3 normal = p_encoded_normal * 2.0 - 1.0; + return normal; +} + +vec3 load_normal(ivec2 p_pos) { + vec3 encoded_normal = imageLoad(source_normal, p_pos).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +vec3 load_normal(ivec2 p_pos, ivec2 p_offset) { + vec3 encoded_normal = imageLoad(source_normal, p_pos + p_offset).xyz; + encoded_normal.z = 1.0 - encoded_normal.z; + return decode_normal(encoded_normal); +} + +// all vectors in viewspace +float calculate_pixel_obscurance(vec3 p_pixel_normal, vec3 p_hit_delta, float p_fallof_sq) { + float length_sq = dot(p_hit_delta, p_hit_delta); + float NdotD = dot(p_pixel_normal, p_hit_delta) / sqrt(length_sq); + + float falloff_mult = max(0.0, length_sq * p_fallof_sq + 1.0); + + return max(0, NdotD - 0.05) * falloff_mult; +} + +void SSIL_tap_inner(const int p_quality_level, inout vec3 r_color_sum, inout float r_obscurance_sum, inout float r_weight_sum, const vec2 p_sampling_uv, const float p_mip_level, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const float p_fallof_sq, const float p_weight_mod) { + // get depth at sample + float viewspace_sample_z = textureLod(source_depth_mipmaps, vec3(p_sampling_uv, params.pass), p_mip_level).x; + vec3 sample_normal = load_normal(ivec2(p_sampling_uv * vec2(params.screen_size))); + + // convert to viewspace + vec3 hit_pos = NDC_to_view_space(p_sampling_uv.xy, viewspace_sample_z); + vec3 hit_delta = hit_pos - p_pix_center_pos; + + float obscurance = calculate_pixel_obscurance(p_pixel_normal, hit_delta, p_fallof_sq); + float weight = 1.0; + + if (p_quality_level >= SSIL_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET) { + float reduct = max(0, -hit_delta.z); + reduct = clamp(reduct * params.neg_inv_radius + 2.0, 0.0, 1.0); + weight = SSIL_HALOING_REDUCTION_AMOUNT * reduct + (1.0 - SSIL_HALOING_REDUCTION_AMOUNT); + } + + // Translate sampling_uv to last screen's coordinates + const vec4 sample_pos = projection_constants.reprojection * vec4(p_sampling_uv * 2.0 - 1.0, (viewspace_sample_z - params.z_near) / (params.z_far - params.z_near) * 2.0 - 1.0, 1.0); + vec2 reprojected_sampling_uv = (sample_pos.xy / sample_pos.w) * 0.5 + 0.5; + + weight *= p_weight_mod; + + r_obscurance_sum += obscurance * weight; + + vec3 sample_color = textureLod(last_frame, reprojected_sampling_uv, 5.0).rgb; + // Reduce impact of fireflies by tonemapping before averaging: http://graphicrants.blogspot.com/2013/12/tone-mapping.html + sample_color /= (1.0 + dot(sample_color, vec3(0.299, 0.587, 0.114))); + r_color_sum += sample_color * obscurance * weight * mix(1.0, smoothstep(0.0, 0.1, -dot(sample_normal, normalize(hit_delta))), params.normal_rejection_amount); + r_weight_sum += weight; +} + +void SSILTap(const int p_quality_level, inout vec3 r_color_sum, inout float r_obscurance_sum, inout float r_weight_sum, const int p_tap_index, const mat2 p_rot_scale, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const vec2 p_normalized_screen_pos, const float p_mip_offset, const float p_fallof_sq, float p_weight_mod, vec2 p_norm_xy, float p_norm_xy_length) { + vec2 sample_offset; + float sample_pow_2_len; + + // patterns + { + vec4 new_sample = sample_pattern[p_tap_index]; + sample_offset = new_sample.xy * p_rot_scale; + sample_pow_2_len = new_sample.w; // precalculated, same as: sample_pow_2_len = log2( length( new_sample.xy ) ); + p_weight_mod *= new_sample.z; + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + sample_offset = round(sample_offset); + + // calculate MIP based on the sample distance from the centre, similar to as described + // in http://graphics.cs.williams.edu/papers/SAOHPG12/. + float mip_level = (p_quality_level < SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset); + + vec2 sampling_uv = sample_offset * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSIL_tap_inner(p_quality_level, r_color_sum, r_obscurance_sum, r_weight_sum, sampling_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); + + // for the second tap, just use the mirrored offset + vec2 sample_offset_mirrored_uv = -sample_offset; + + // tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + if (p_quality_level >= SSIL_TILT_SAMPLES_ENABLE_AT_QUALITY_PRESET) { + float dot_norm = dot(sample_offset_mirrored_uv, p_norm_xy); + sample_offset_mirrored_uv -= dot_norm * p_norm_xy_length * p_norm_xy; + sample_offset_mirrored_uv = round(sample_offset_mirrored_uv); + } + + // snap to pixel center (more correct obscurance math, avoids artifacts) + vec2 sampling_mirrored_uv = sample_offset_mirrored_uv * params.half_screen_pixel_size + p_normalized_screen_pos; + + SSIL_tap_inner(p_quality_level, r_color_sum, r_obscurance_sum, r_weight_sum, sampling_mirrored_uv, mip_level, p_pix_center_pos, p_pixel_normal, p_fallof_sq, p_weight_mod); +} + +void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, out float r_weight, const vec2 p_pos, int p_quality_level, bool p_adaptive_base) { + vec2 pos_rounded = trunc(p_pos); + uvec2 upos = uvec2(pos_rounded); + + const int number_of_taps = (p_adaptive_base) ? (SSIL_ADAPTIVE_TAP_BASE_COUNT) : (num_taps[p_quality_level]); + float pix_z, pix_left_z, pix_top_z, pix_right_z, pix_bottom_z; + + vec4 valuesUL = textureGather(source_depth_mipmaps, vec3(pos_rounded * params.half_screen_pixel_size, params.pass)); + vec4 valuesBR = textureGather(source_depth_mipmaps, vec3((pos_rounded + vec2(1.0)) * params.half_screen_pixel_size, params.pass)); + + // get this pixel's viewspace depth + pix_z = valuesUL.y; + + // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0) + pix_left_z = valuesUL.x; + pix_top_z = valuesUL.z; + pix_right_z = valuesBR.z; + pix_bottom_z = valuesBR.x; + + vec2 normalized_screen_pos = pos_rounded * params.half_screen_pixel_size + params.half_screen_pixel_size_x025; + vec3 pix_center_pos = NDC_to_view_space(normalized_screen_pos, pix_z); + + // Load this pixel's viewspace normal + uvec2 full_res_coord = upos * 2 * params.size_multiplier + params.pass_coord_offset.xy; + vec3 pixel_normal = load_normal(ivec2(full_res_coord)); + + const vec2 pixel_size_at_center = NDC_to_view_space(normalized_screen_pos.xy + params.half_screen_pixel_size, pix_center_pos.z).xy - pix_center_pos.xy; + + float pixel_lookup_radius; + float fallof_sq; + + // calculate effect radius and fit our screen sampling pattern inside it + float viewspace_radius; + calculate_radius_parameters(length(pix_center_pos), pixel_size_at_center, pixel_lookup_radius, viewspace_radius, fallof_sq); + + // calculate samples rotation/scaling + mat2 rot_scale_matrix; + uint pseudo_random_index; + + { + vec4 rotation_scale; + // reduce effect radius near the screen edges slightly; ideally, one would render a larger depth buffer (5% on each side) instead + if (!p_adaptive_base && (p_quality_level >= SSIL_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET)) { + float near_screen_border = min(min(normalized_screen_pos.x, 1.0 - normalized_screen_pos.x), min(normalized_screen_pos.y, 1.0 - normalized_screen_pos.y)); + near_screen_border = clamp(10.0 * near_screen_border + 0.6, 0.0, 1.0); + pixel_lookup_radius *= near_screen_border; + } + + // load & update pseudo-random rotation matrix + pseudo_random_index = uint(pos_rounded.y * 2 + pos_rounded.x) % 5; + rotation_scale = constants.rotation_matrices[params.pass * 5 + pseudo_random_index]; + rot_scale_matrix = mat2(rotation_scale.x * pixel_lookup_radius, rotation_scale.y * pixel_lookup_radius, rotation_scale.z * pixel_lookup_radius, rotation_scale.w * pixel_lookup_radius); + } + + // the main obscurance & sample weight storage + vec3 color_sum = vec3(0.0); + float obscurance_sum = 0.0; + float weight_sum = 0.0; + + // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); + + // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats + pix_center_pos *= 0.9992; + + if (!p_adaptive_base && (p_quality_level >= SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z); + } + + const float global_mip_offset = SSIL_DEPTH_MIPS_GLOBAL_OFFSET; + float mip_offset = (p_quality_level < SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (log2(pixel_lookup_radius) + global_mip_offset); + + // Used to tilt the second set of samples so that the disk is effectively rotated by the normal + // effective at removing one set of artifacts, but too expensive for lower quality settings + vec2 norm_xy = vec2(pixel_normal.x, pixel_normal.y); + float norm_xy_length = length(norm_xy); + norm_xy /= vec2(norm_xy_length, -norm_xy_length); + norm_xy_length *= SSIL_TILT_SAMPLES_AMOUNT; + + // standard, non-adaptive approach + if ((p_quality_level != 3) || p_adaptive_base) { + for (int i = 0; i < number_of_taps; i++) { + SSILTap(p_quality_level, color_sum, obscurance_sum, weight_sum, i, rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, 1.0, norm_xy, norm_xy_length); + } + } +#ifdef ADAPTIVE + else { + // add new ones if needed + vec2 full_res_uv = normalized_screen_pos + params.pass_uv_offset.xy; + float importance = textureLod(source_importance, full_res_uv, 0.0).x; + + //Need to store obscurance from base pass + // load existing base values + vec4 base_values = imageLoad(source_ssil, ivec3(upos, params.pass)); + weight_sum += imageLoad(edges_weights_image, ivec2(upos)).r * float(SSIL_ADAPTIVE_TAP_BASE_COUNT * 4.0); + color_sum += (base_values.rgb) * weight_sum; + obscurance_sum += (base_values.a) * weight_sum; + + // increase importance around edges + float edge_count = dot(1.0 - edgesLRTB, vec4(1.0, 1.0, 1.0, 1.0)); + + float avg_total_importance = float(counter.sum) * params.load_counter_avg_div; + + float importance_limiter = clamp(params.adaptive_sample_limit / avg_total_importance, 0.0, 1.0); + importance *= importance_limiter; + + float additional_sample_count = SSIL_ADAPTIVE_TAP_FLEXIBLE_COUNT * importance; + + const float blend_range = 3.0; + const float blend_range_inv = 1.0 / blend_range; + + additional_sample_count += 0.5; + uint additional_samples = uint(additional_sample_count); + uint additional_samples_to = min(SSIL_MAX_TAPS, additional_samples + SSIL_ADAPTIVE_TAP_BASE_COUNT); + + for (uint i = SSIL_ADAPTIVE_TAP_BASE_COUNT; i < additional_samples_to; i++) { + additional_sample_count -= 1.0f; + float weight_mod = clamp(additional_sample_count * blend_range_inv, 0.0, 1.0); + SSILTap(p_quality_level, color_sum, obscurance_sum, weight_sum, int(i), rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, weight_mod, norm_xy, norm_xy_length); + } + } +#endif + + // Early out for adaptive base + if (p_adaptive_base) { + vec3 color = color_sum / weight_sum; + + r_color = color; + r_edges = vec4(0.0); + r_obscurance = obscurance_sum / weight_sum; + r_weight = weight_sum; + return; + } + + // Calculate weighted average + vec3 color = color_sum / weight_sum; + color /= 1.0 - dot(color, vec3(0.299, 0.587, 0.114)); + + // Calculate fadeout (1 close, gradient, 0 far) + float fade_out = clamp(pix_center_pos.z * params.fade_out_mul + params.fade_out_add, 0.0, 1.0); + + // Reduce the SSIL if we're on the edge to remove artifacts on edges (we don't care for the lower quality one) + if (!p_adaptive_base && (p_quality_level >= SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + // when there's more than 2 opposite edges, start fading out the occlusion to reduce aliasing artifacts + float edge_fadeout_factor = clamp((1.0 - edgesLRTB.x - edgesLRTB.y) * 0.35, 0.0, 1.0) + clamp((1.0 - edgesLRTB.z - edgesLRTB.w) * 0.35, 0.0, 1.0); + + fade_out *= clamp(1.0 - edge_fadeout_factor, 0.0, 1.0); + } + + color = params.intensity * color; + + color *= fade_out; + + // outputs! + r_color = color; + r_edges = edgesLRTB; // These are used to prevent blurring across edges, 1 means no edge, 0 means edge, 0.5 means half way there, etc. + r_obscurance = clamp((obscurance_sum / weight_sum) * params.intensity, 0.0, 1.0); + r_weight = weight_sum; +} + +void main() { + vec3 out_color; + float out_obscurance; + float out_weight; + vec4 out_edges; + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing + return; + } + + vec2 uv = vec2(gl_GlobalInvocationID) + vec2(0.5); +#ifdef SSIL_BASE + generate_SSIL(out_color, out_edges, out_obscurance, out_weight, uv, params.quality, true); + + imageStore(dest_image, ssC, vec4(out_color, out_obscurance)); + imageStore(edges_weights_image, ssC, vec4(out_weight / (float(SSIL_ADAPTIVE_TAP_BASE_COUNT) * 4.0))); +#else + generate_SSIL(out_color, out_edges, out_obscurance, out_weight, uv, params.quality, false); // pass in quality levels + + imageStore(dest_image, ssC, vec4(out_color, out_obscurance)); + imageStore(edges_weights_image, ssC, vec4(pack_edges(out_edges))); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssil_blur.glsl b/servers/rendering/renderer_rd/shaders/ssil_blur.glsl new file mode 100644 index 0000000000..11861e261f --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil_blur.glsl @@ -0,0 +1,124 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D source_ssil; + +layout(rgba16, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +layout(r8, set = 2, binding = 0) uniform restrict readonly image2D source_edges; + +layout(push_constant, binding = 1, std430) uniform Params { + float edge_sharpness; + float pad; + vec2 half_screen_pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.edge_sharpness, 0.0, 1.0); +} + +void add_sample(vec4 p_ssil_value, float p_edge_value, inout vec4 r_sum, inout float r_sum_weight) { + float weight = p_edge_value; + + r_sum += (weight * p_ssil_value); + r_sum_weight += weight; +} + +#ifdef MODE_WIDE +vec4 sample_blurred_wide(ivec2 p_pos, vec2 p_coord) { + vec4 ssil_value = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 0)); + vec4 ssil_valueL = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(-2, 0)); + vec4 ssil_valueT = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, -2)); + vec4 ssil_valueR = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(2, 0)); + vec4 ssil_valueB = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 2)); + + vec4 edgesLRTB = unpack_edges(imageLoad(source_edges, p_pos).r); + edgesLRTB.x *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(-2, 0)).r).y; + edgesLRTB.z *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(0, -2)).r).w; + edgesLRTB.y *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(2, 0)).r).x; + edgesLRTB.w *= unpack_edges(imageLoad(source_edges, p_pos + ivec2(0, 2)).r).z; + + float sum_weight = 0.8; + vec4 sum = ssil_value * sum_weight; + + add_sample(ssil_valueL, edgesLRTB.x, sum, sum_weight); + add_sample(ssil_valueR, edgesLRTB.y, sum, sum_weight); + add_sample(ssil_valueT, edgesLRTB.z, sum, sum_weight); + add_sample(ssil_valueB, edgesLRTB.w, sum, sum_weight); + + vec4 ssil_avg = sum / sum_weight; + + ssil_value = ssil_avg; + + return ssil_value; +} +#endif + +#ifdef MODE_SMART +vec4 sample_blurred(ivec2 p_pos, vec2 p_coord) { + vec4 vC = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 0)); + vec4 vL = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(-1, 0)); + vec4 vT = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, -1)); + vec4 vR = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(1, 0)); + vec4 vB = textureLodOffset(source_ssil, vec2(p_coord), 0.0, ivec2(0, 1)); + + float packed_edges = imageLoad(source_edges, p_pos).r; + vec4 edgesLRTB = unpack_edges(packed_edges); + + float sum_weight = 0.5; + vec4 sum = vC * sum_weight; + + add_sample(vL, edgesLRTB.x, sum, sum_weight); + add_sample(vR, edgesLRTB.y, sum, sum_weight); + add_sample(vT, edgesLRTB.z, sum, sum_weight); + add_sample(vB, edgesLRTB.w, sum, sum_weight); + + vec4 ssil_avg = sum / sum_weight; + + vec4 ssil_value = ssil_avg; + + return ssil_value; +} +#endif + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef MODE_NON_SMART + + vec2 half_pixel = params.half_screen_pixel_size * 0.5; + + vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size; + + vec4 centre = textureLod(source_ssil, uv, 0.0); + + vec4 value = textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x * 3, -half_pixel.y)), 0.0) * 0.2; + value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x, -half_pixel.y * 3)), 0.0) * 0.2; + value += textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x, +half_pixel.y * 3)), 0.0) * 0.2; + value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x * 3, +half_pixel.y)), 0.0) * 0.2; + + vec4 sampled = value + centre * 0.2; + +#else +#ifdef MODE_SMART + vec4 sampled = sample_blurred(ssC, (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#else // MODE_WIDE + vec4 sampled = sample_blurred_wide(ssC, (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size); +#endif +#endif // MODE_NON_SMART + imageStore(dest_image, ssC, sampled); +} diff --git a/servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl new file mode 100644 index 0000000000..815aa55fd4 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2016, Intel Corporation +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of +// the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// File changes (yyyy-mm-dd) +// 2016-09-07: filip.strugar@intel.com: first commit +// 2020-12-05: clayjohn: convert to Vulkan and Godot +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#ifdef GENERATE_MAP +layout(set = 0, binding = 0) uniform sampler2DArray source_texture; +#else +layout(set = 0, binding = 0) uniform sampler2D source_importance; +#endif +layout(r8, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; + +#ifdef PROCESS_MAPB +layout(set = 2, binding = 0, std430) buffer Counter { + uint sum; +} +counter; +#endif + +layout(push_constant, binding = 1, std430) uniform Params { + vec2 half_screen_pixel_size; + float intensity; + float pad; +} +params; + +void main() { + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + +#ifdef GENERATE_MAP + // importance map stuff + uvec2 base_position = ssC * 2; + + float avg = 0.0; + float minV = 1.0; + float maxV = 0.0; + for (int i = 0; i < 4; i++) { + vec3 value_a = texelFetch(source_texture, ivec3(base_position, i), 0).rgb * params.intensity; + vec3 value_b = texelFetch(source_texture, ivec3(base_position, i) + ivec3(0, 1, 0), 0).rgb * params.intensity; + vec3 value_c = texelFetch(source_texture, ivec3(base_position, i) + ivec3(1, 0, 0), 0).rgb * params.intensity; + vec3 value_d = texelFetch(source_texture, ivec3(base_position, i) + ivec3(1, 1, 0), 0).rgb * params.intensity; + + // Calculate luminance (black and white value) + float a = dot(value_a, vec3(0.2125, 0.7154, 0.0721)); + float b = dot(value_b, vec3(0.2125, 0.7154, 0.0721)); + float c = dot(value_c, vec3(0.2125, 0.7154, 0.0721)); + float d = dot(value_d, vec3(0.2125, 0.7154, 0.0721)); + + maxV = max(maxV, max(max(a, b), max(c, d))); + minV = min(minV, min(min(a, b), min(c, d))); + } + + float min_max_diff = maxV - minV; + + imageStore(dest_image, ssC, vec4(pow(clamp(min_max_diff * 2.0, 0.0, 1.0), 0.6))); +#endif + +#ifdef PROCESS_MAPA + vec2 uv = (vec2(ssC) + 0.5) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, +half_pixel.y), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x, +half_pixel.y * 3), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); +#endif + +#ifdef PROCESS_MAPB + vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0; + + float centre = textureLod(source_importance, uv, 0.0).x; + + vec2 half_pixel = params.half_screen_pixel_size; + + vec4 vals; + vals.x = textureLod(source_importance, uv + vec2(-half_pixel.x, -half_pixel.y * 3), 0.0).x; + vals.y = textureLod(source_importance, uv + vec2(+half_pixel.x * 3, -half_pixel.y), 0.0).x; + vals.z = textureLod(source_importance, uv + vec2(+half_pixel.x, +half_pixel.y * 3), 0.0).x; + vals.w = textureLod(source_importance, uv + vec2(-half_pixel.x * 3, +half_pixel.y), 0.0).x; + + float avg = dot(vals, vec4(0.25, 0.25, 0.25, 0.25)); + + imageStore(dest_image, ssC, vec4(avg)); + + // sum the average; to avoid overflowing we assume max AO resolution is not bigger than 16384x16384; so quarter res (used here) will be 4096x4096, which leaves us with 8 bits per pixel + uint sum = uint(clamp(avg, 0.0, 1.0) * 255.0 + 0.5); + + // save every 9th to avoid InterlockedAdd congestion - since we're blurring, this is good enough; compensated by multiplying load_counter_avg_div by 9 + if (((ssC.x % 3) + (ssC.y % 3)) == 0) { + atomicAdd(counter.sum, sum); + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/ssil_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssil_interleave.glsl new file mode 100644 index 0000000000..8a7a5ae4fd --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/ssil_interleave.glsl @@ -0,0 +1,102 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(rgba16, set = 0, binding = 0) uniform restrict writeonly image2D dest_image; +layout(set = 1, binding = 0) uniform sampler2DArray source_texture; +layout(r8, set = 2, binding = 0) uniform restrict readonly image2DArray source_edges; + +layout(push_constant, binding = 1, std430) uniform Params { + float inv_sharpness; + uint size_modifier; + vec2 pixel_size; +} +params; + +vec4 unpack_edges(float p_packed_val) { + uint packed_val = uint(p_packed_val * 255.5); + vec4 edgesLRTB; + edgesLRTB.x = float((packed_val >> 6) & 0x03) / 3.0; + edgesLRTB.y = float((packed_val >> 4) & 0x03) / 3.0; + edgesLRTB.z = float((packed_val >> 2) & 0x03) / 3.0; + edgesLRTB.w = float((packed_val >> 0) & 0x03) / 3.0; + + return clamp(edgesLRTB + params.inv_sharpness, 0.0, 1.0); +} + +void main() { + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(ssC, ivec2(1.0 / params.pixel_size)))) { //too large, do nothing + return; + } + +#ifdef MODE_SMART + uvec2 pix_pos = uvec2(gl_GlobalInvocationID.xy); + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; + + // calculate index in the four deinterleaved source array texture + int mx = int(pix_pos.x % 2); + int my = int(pix_pos.y % 2); + int index_center = mx + my * 2; // center index + int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal + int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical + int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal + + vec4 color = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0); + + vec4 edgesLRTB = unpack_edges(imageLoad(source_edges, ivec3(pix_pos / uvec2(params.size_modifier), index_center)).r); + + // convert index shifts to sampling offsets + float fmx = float(mx); + float fmy = float(my); + + // in case of an edge, push sampling offsets away from the edge (towards pixel center) + float fmxe = (edgesLRTB.y - edgesLRTB.x); + float fmye = (edgesLRTB.w - edgesLRTB.z); + + // calculate final sampling offsets and sample using bilinear filter + vec2 uv_horizontal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx + fmxe - 0.5, 0.5 - fmy)) * params.pixel_size; + vec4 color_horizontal = textureLod(source_texture, vec3(uv_horizontal, index_horizontal), 0.0); + vec2 uv_vertical = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(0.5 - fmx, fmy - 0.5 + fmye)) * params.pixel_size; + vec4 color_vertical = textureLod(source_texture, vec3(uv_vertical, index_vertical), 0.0); + vec2 uv_diagonal = (gl_GlobalInvocationID.xy + vec2(0.5) + vec2(fmx - 0.5 + fmxe, fmy - 0.5 + fmye)) * params.pixel_size; + vec4 color_diagonal = textureLod(source_texture, vec3(uv_diagonal, index_diagonal), 0.0); + + // reduce weight for samples near edge - if the edge is on both sides, weight goes to 0 + vec4 blendWeights; + blendWeights.x = 1.0; + blendWeights.y = (edgesLRTB.x + edgesLRTB.y) * 0.5; + blendWeights.z = (edgesLRTB.z + edgesLRTB.w) * 0.5; + blendWeights.w = (blendWeights.y + blendWeights.z) * 0.5; + + // calculate weighted average + float blendWeightsSum = dot(blendWeights, vec4(1.0, 1.0, 1.0, 1.0)); + color += color_horizontal * blendWeights.y; + color += color_vertical * blendWeights.z; + color += color_diagonal * blendWeights.w; + color /= blendWeightsSum; + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), color); +#else // !MODE_SMART + + vec2 uv = (gl_GlobalInvocationID.xy + vec2(0.5)) * params.pixel_size; +#ifdef MODE_HALF + vec4 a = textureLod(source_texture, vec3(uv, 0), 0.0); + vec4 d = textureLod(source_texture, vec3(uv, 3), 0.0); + vec4 avg = (a + d) * 0.5; + +#else + vec4 a = textureLod(source_texture, vec3(uv, 0), 0.0); + vec4 b = textureLod(source_texture, vec3(uv, 1), 0.0); + vec4 c = textureLod(source_texture, vec3(uv, 2), 0.0); + vec4 d = textureLod(source_texture, vec3(uv, 3), 0.0); + vec4 avg = (a + b + c + d) * 0.25; + +#endif + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), avg); +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl index 747f88960c..7c8d4f7f99 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl @@ -76,19 +76,15 @@ layout(set = 0, binding = 10) uniform sampler shadow_sampler; #define MAX_VOXEL_GI_INSTANCES 8 struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; + mat4 xform; // 64 - 64 - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; + vec3 bounds; // 12 - 76 + float dynamic_range; // 4 - 80 - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; - uint mipmaps; + float bias; // 4 - 84 + float normal_bias; // 4 - 88 + bool blend_ambient; // 4 - 92 + uint mipmaps; // 4 - 96 }; layout(set = 0, binding = 11, std140) uniform VoxelGIs { @@ -581,16 +577,29 @@ void main() { if (spot_lights.data[light_index].shadow_enabled) { //has shadow - vec4 v = vec4(view_pos, 1.0); + vec4 uv_rect = spot_lights.data[light_index].atlas_rect; + vec2 flip_offset = spot_lights.data[light_index].direction.xy; - vec4 splane = (spot_lights.data[light_index].shadow_matrix * v); - splane /= splane.w; + vec3 local_vert = (spot_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; + float shadow_len = length(local_vert); //need to remember shadow len from here + vec3 shadow_sample = normalize(local_vert); - shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); - } + if (shadow_sample.z >= 0.0) { + uv_rect.xy += flip_offset; + } + shadow_sample.z = 1.0 + abs(shadow_sample.z); + vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - spot_lights.data[light_index].shadow_bias); + pos.z *= spot_lights.data[light_index].inv_radius; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); + } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g); } } diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl index 779f04ed35..73a97d9df1 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl @@ -13,7 +13,6 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; #ifndef MODE_DYNAMIC #define NO_CHILDREN 0xFFFFFFFF -#define GREY_VEC vec3(0.33333, 0.33333, 0.33333) struct CellChildren { uint children[8]; diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl index 281c496df3..3f3437f527 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl @@ -90,66 +90,10 @@ void main() { #endif #ifdef MODE_DEBUG_LIGHT - -#ifdef USE_ANISOTROPY - -#define POS_X 0 -#define POS_Y 1 -#define POS_Z 2 -#define NEG_X 3 -#define NEG_Y 4 -#define NEG_Z 5 - - const uint triangle_aniso[12] = uint[]( - NEG_X, - NEG_Z, - NEG_Y, - NEG_Z, - NEG_X, - NEG_Y, - POS_Z, - POS_X, - POS_X, - POS_Y, - POS_Y, - POS_Z); - - color_interp.xyz = texelFetch(sampler3D(color_tex, tex_sampler), ivec3(posu), int(params.level)).xyz * params.dynamic_range; - vec3 aniso_pos = texelFetch(sampler3D(aniso_pos_tex, tex_sampler), ivec3(posu), int(params.level)).xyz; - vec3 aniso_neg = texelFetch(sampler3D(aniso_neg_tex, tex_sampler), ivec3(posu), int(params.level)).xyz; - uint side = triangle_aniso[gl_VertexIndex / 3]; - - float strength = 0.0; - switch (side) { - case POS_X: - strength = aniso_pos.x; - break; - case POS_Y: - strength = aniso_pos.y; - break; - case POS_Z: - strength = aniso_pos.z; - break; - case NEG_X: - strength = aniso_neg.x; - break; - case NEG_Y: - strength = aniso_neg.y; - break; - case NEG_Z: - strength = aniso_neg.z; - break; - } - - color_interp.xyz *= strength; - -#else color_interp = texelFetch(sampler3D(color_tex, tex_sampler), ivec3(posu), int(params.level)); color_interp.xyz *params.dynamic_range; - #endif -#endif float scale = (1 << params.level); gl_Position = params.projection * vec4((vec3(posu) + vertex) * scale, 1.0); diff --git a/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl index e20b3f680d..3bb4421646 100644 --- a/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl @@ -6,10 +6,9 @@ layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; -#define MAX_DISTANCE 100000 +#define MAX_DISTANCE 100000.0 #define NO_CHILDREN 0xFFFFFFFF -#define GREY_VEC vec3(0.33333, 0.33333, 0.33333) struct CellChildren { uint children[8]; @@ -44,7 +43,7 @@ params; void main() { vec3 pos = vec3(gl_GlobalInvocationID); - float closest_dist = 100000.0; + float closest_dist = MAX_DISTANCE; for (uint i = params.offset; i < params.end; i++) { vec3 posu = vec3(uvec3(cell_data.data[i].position & 0x7FF, (cell_data.data[i].position >> 11) & 0x3FF, cell_data.data[i].position >> 21)); |