diff --git a/scripts/startup/bl_ui/properties_render.py b/scripts/startup/bl_ui/properties_render.py index fdc749a3efe..75b61cba3ff 100644 --- a/scripts/startup/bl_ui/properties_render.py +++ b/scripts/startup/bl_ui/properties_render.py @@ -628,10 +628,13 @@ class RENDER_PT_eevee_next_gi_approximation(RenderButtonsPanel, Panel): col = layout.column(align=True) col.prop(props, "fast_gi_ray_count", text="Rays") col.prop(props, "fast_gi_step_count", text="Steps") + col.prop(props, "horizon_quality", text="Precision") + + col = layout.column(align=True) + col.prop(props, "fast_gi_distance") + col.prop(props, "fast_gi_thickness_near", text="Thickness Near") + col.prop(props, "fast_gi_thickness_far", text="Far") - layout.prop(props, "horizon_quality", text="Precision") - layout.prop(props, "fast_gi_distance") - layout.prop(props, "horizon_thickness", text="Thickness") layout.prop(props, "horizon_bias", text="Bias") diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 58cc474a772..7e8598cb7a1 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -29,7 +29,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 45 +#define BLENDER_FILE_SUBVERSION 46 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index 3caee3eabb0..6cd2f7f347a 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -3664,6 +3664,14 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 46)) { + const Scene *default_scene = DNA_struct_default_get(Scene); + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + scene->eevee.fast_gi_thickness_near = default_scene->eevee.fast_gi_thickness_near; + scene->eevee.fast_gi_thickness_far = default_scene->eevee.fast_gi_thickness_far; + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/draw/engines/eevee_next/eevee_ambient_occlusion.cc b/source/blender/draw/engines/eevee_next/eevee_ambient_occlusion.cc index 73ef72c9e2d..d20db01ab25 100644 --- a/source/blender/draw/engines/eevee_next/eevee_ambient_occlusion.cc +++ b/source/blender/draw/engines/eevee_next/eevee_ambient_occlusion.cc @@ -43,8 +43,9 @@ void AmbientOcclusion::init() data_.distance = sce_eevee.gtao_distance; data_.gi_distance = (sce_eevee.fast_gi_distance > 0.0f) ? sce_eevee.fast_gi_distance : 1e16f; data_.lod_factor = 1.0f / (1.0f + sce_eevee.gtao_quality * 4.0f); - data_.thickness = sce_eevee.gtao_thickness; data_.angle_bias = 1.0 / max_ff(1e-8f, 1.0 - sce_eevee.gtao_focus); + data_.thickness_near = sce_eevee.fast_gi_thickness_near; + data_.thickness_far = sce_eevee.fast_gi_thickness_far; /* Size is multiplied by 2 because it is applied in NDC [-1..1] range. */ data_.pixel_size = float2(2.0f) / float2(inst_.film.render_extent_get()); } diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index 48efab4f16d..d7117d06777 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -1934,10 +1934,10 @@ struct AOData { float distance; float lod_factor; - float thickness; + float thickness_near; + float thickness_far; float angle_bias; float gi_distance; - float _pad2; }; BLI_STATIC_ASSERT_ALIGN(AOData, 16) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_ambient_occlusion_pass_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_ambient_occlusion_pass_comp.glsl index 45537ec67b7..e4a5df94a53 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_ambient_occlusion_pass_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_ambient_occlusion_pass_comp.glsl @@ -36,7 +36,8 @@ void main() noise, uniform_buf.ao.pixel_size, uniform_buf.ao.distance, - uniform_buf.ao.thickness, + uniform_buf.ao.thickness_near, + uniform_buf.ao.thickness_far, uniform_buf.ao.angle_bias, 2, 10, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl index 0ef1c1b045a..dc2e6d833dc 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_comp.glsl @@ -51,7 +51,8 @@ void main() noise, uniform_buf.ao.pixel_size, uniform_buf.ao.gi_distance, - uniform_buf.ao.thickness, + uniform_buf.ao.thickness_near, + uniform_buf.ao.thickness_far, uniform_buf.ao.angle_bias, fast_gi_slice_count, fast_gi_step_count, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_eval_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_eval_lib.glsl index 4e5484cb2b5..ded3bec739a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_eval_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_scan_eval_lib.glsl @@ -49,36 +49,6 @@ vec3 horizon_scan_sample_normal(vec2 uv) #endif } -/** - * Returns the start and end point of a ray clipped to its intersection - * with a sphere. - */ -void horizon_scan_occluder_intersection_ray_sphere_clip(Ray ray, - Sphere sphere, - out vec3 P_entry, - out vec3 P_exit) -{ - vec3 f = ray.origin - sphere.center; - float a = length_squared(ray.direction); - float b = 2.0 * dot(ray.direction, f); - float c = length_squared(f) - square(sphere.radius); - float determinant = b * b - 4.0 * a * c; - if (determinant <= 0.0) { - /* No intersection. Return null segment. */ - P_entry = P_exit = ray.origin; - return; - } - /* Using fast sqrt_fast doesn't seem to cause artifact here. */ - float t_min = (-b - sqrt_fast(determinant)) / (2.0 * a); - float t_max = (-b + sqrt_fast(determinant)) / (2.0 * a); - /* Clip segment to the intersection range. */ - float t_entry = clamp(0.0, t_min, t_max); - float t_exit = clamp(ray.max_time, t_min, t_max); - - P_entry = ray.origin + ray.direction * t_entry; - P_exit = ray.origin + ray.direction * t_exit; -} - struct HorizonScanResult { #ifdef HORIZON_OCCLUSION float result; @@ -98,7 +68,8 @@ HorizonScanResult horizon_scan_eval(vec3 vP, vec2 noise, vec2 pixel_size, float search_distance, - float global_thickness, + float thickness_near, + float thickness_far, float angle_bias, const int slice_count, const int sample_count, @@ -184,31 +155,23 @@ HorizonScanResult horizon_scan_eval(vec3 vP, sample_depth += reversed ? -bias : bias; vec3 vP_sample = drw_point_screen_to_view(vec3(sample_uv, sample_depth)); - vec3 vV_sample = drw_view_incident_vector(vP_sample); - Ray ray; - ray.origin = vP_sample; - ray.direction = -vV_sample; - ray.max_time = global_thickness; - - if (reversed) { - /* Make the ray start above the surface and end exactly at the surface. */ - ray.max_time = 2.0 * distance(vP, vP_sample); - ray.origin = vP_sample + vV_sample * ray.max_time; - ray.direction = -vV_sample; + float sample_distance; + vec3 vL_front = normalize_and_get_length(vP_sample - vP, sample_distance); + if (sample_distance > search_distance) { + continue; } - Sphere sphere = shape_sphere(vP, search_distance); - - vec3 vP_front = ray.origin, vP_back = ray.origin + ray.direction * ray.max_time; - horizon_scan_occluder_intersection_ray_sphere_clip(ray, sphere, vP_front, vP_back); - - vec3 vL_front = normalize(vP_front - vP); - vec3 vL_back = normalize(vP_back - vP); + vec3 vL_back = normalize_and_get_length((vP_sample - vV * thickness_near) - vP, + sample_distance); + if (sample_distance > search_distance) { + continue; + } /* Ordered pair of angle. Minimum in X, Maximum in Y. * Front will always have the smallest angle here since it is the closest to the view. */ vec2 theta = acos_fast(vec2(dot(vL_front, vV), dot(vL_back, vV))); + theta.y = max(theta.x + thickness_far, theta.y); /* If we are tracing backward, the angles are negative. Swizzle to keep correct order. */ theta = (side == 0) ? theta.xy : -theta.yx; @@ -216,7 +179,7 @@ HorizonScanResult horizon_scan_eval(vec3 vP, /* Take emitter surface normal into consideration. */ vec3 sample_normal = horizon_scan_sample_normal(sample_uv); /* Discard back-facing samples. - * The 2 factor is to avoid loosing too much energy (which is something not + * The 2 factor is to avoid loosing too much energy v(which is something not * explained in the paper...). Likely to be wrong, but we need a soft falloff. */ float facing_weight = saturate(-dot(sample_normal, vL_front) * 2.0); @@ -227,8 +190,6 @@ HorizonScanResult horizon_scan_eval(vec3 vP, ~slice_bitmask); sample_radiance *= facing_weight * weight_bitmask; - /* Encoding using front sample direction gives better result than - * `normalize(vL_front + vL_back)` */ spherical_harmonics_encode_signal_sample( vL_front, vec4(sample_radiance, weight_bitmask), sh_slice); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 22c71b305ea..72905e25fcd 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -370,7 +370,8 @@ float ambient_occlusion_eval(vec3 normal, noise, uniform_buf.ao.pixel_size, max_distance, - uniform_buf.ao.thickness, + uniform_buf.ao.thickness_near, + uniform_buf.ao.thickness_far, uniform_buf.ao.angle_bias, 2, 10, diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index bbb1cc36e7e..3508583ee33 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -216,6 +216,8 @@ .fast_gi_step_count = 8, \ .fast_gi_ray_count = 2, \ .fast_gi_distance = 0.0f, \ + .fast_gi_thickness_near = 0.25f, \ + .fast_gi_thickness_far = DEG2RAD(45), \ .fast_gi_method = FAST_GI_FULL, \ \ .bokeh_overblur = 5.0f, \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 84ef3815ce5..eaca57f800c 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1867,6 +1867,8 @@ typedef struct SceneEEVEE { int fast_gi_step_count; int fast_gi_ray_count; float fast_gi_distance; + float fast_gi_thickness_near; + float fast_gi_thickness_far; char fast_gi_method; char _pad0[3]; diff --git a/source/blender/makesrna/intern/rna_scene.cc b/source/blender/makesrna/intern/rna_scene.cc index 1412093a946..3b3b75663b8 100644 --- a/source/blender/makesrna/intern/rna_scene.cc +++ b/source/blender/makesrna/intern/rna_scene.cc @@ -8294,16 +8294,27 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr); - /* Horizon Scan */ + /* Fast GI approximation */ - prop = RNA_def_property(srna, "horizon_thickness", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_sdna(prop, nullptr, "gtao_thickness"); - RNA_def_property_ui_text(prop, - "Thickness", - "Constant thickness of the surfaces considered when doing horizon scan " - "and by extension ambient occlusion"); - RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + prop = RNA_def_property(srna, "fast_gi_thickness_near", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_ui_text( + prop, + "Near Thickness", + "Geometric thickness of the surfaces when computing fast GI and ambient occlusion. " + "Reduces light leaking and missing contact occlusion"); + RNA_def_property_range(prop, 0.0f, 100000.0f); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1.0f, 3); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr); + + prop = RNA_def_property(srna, "fast_gi_thickness_far", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_ui_text( + prop, + "Far Thickness", + "Angular thickness of the surfaces when computing fast GI and ambient occlusion. " + "Reduces energy loss and missing occlusion of far geometry"); + RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f)); + RNA_def_property_ui_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f), 10.0f, 3); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);