EEVEE: Occlusion: Use ScreenSpaceRay for iteration
The sampling is now optimum with every samples being at least one pixel appart. Also use a squared repartition to improve the sampling near the center. This also removes the thickness heuristic since it seems to remove a lot of details and bias the AO too much.
This commit is contained in:
parent
5db5966cdb
commit
0983e66e03
|
@ -62,7 +62,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
|
|||
|
||||
common_data->ao_dist = scene_eval->eevee.gtao_distance;
|
||||
common_data->ao_factor = scene_eval->eevee.gtao_factor;
|
||||
common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality;
|
||||
common_data->ao_quality = scene_eval->eevee.gtao_quality;
|
||||
|
||||
if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
|
||||
common_data->ao_settings = 1.0f; /* USE_AO */
|
||||
|
|
|
@ -31,7 +31,6 @@ uniform sampler2D horizonBuffer;
|
|||
#define USE_BENT_NORMAL 2
|
||||
#define USE_DENOISE 4
|
||||
|
||||
#define MAX_LOD 6.0
|
||||
#define NO_OCCLUSION_DATA OcclusionData(vec4(M_PI, -M_PI, M_PI, -M_PI), 1.0)
|
||||
|
||||
struct OcclusionData {
|
||||
|
@ -77,25 +76,38 @@ vec2 get_ao_dir(float jitter)
|
|||
float search_horizon(vec3 vI,
|
||||
vec3 vP,
|
||||
float noise,
|
||||
vec2 uv_start,
|
||||
vec2 uv_dir,
|
||||
ScreenSpaceRay ssray,
|
||||
sampler2D depth_tx,
|
||||
const float inverted,
|
||||
float radius,
|
||||
const float sample_count)
|
||||
{
|
||||
float sample_count_inv = 1.0 / sample_count;
|
||||
/* Init at cos(M_PI). */
|
||||
float h = (inverted != 0.0) ? 1.0 : -1.0;
|
||||
|
||||
/* TODO(fclem) samples steps should be using the same approach as raytrace. (DDA line algo.) */
|
||||
for (float i = 0.0; i < sample_count; i++) {
|
||||
float t = ((i + noise) * sample_count_inv);
|
||||
vec2 uv = uv_start + uv_dir * t;
|
||||
float lod = min(MAX_LOD, max(i - noise, 0.0) * aoQuality);
|
||||
ssray.max_time -= 1.0;
|
||||
|
||||
if (ssray.max_time <= 2.0) {
|
||||
/* Produces self shadowing under this threshold. */
|
||||
return fast_acos(h);
|
||||
}
|
||||
|
||||
float prev_time, time = 0.0;
|
||||
for (float iter = 0.0; time < ssray.max_time && iter < sample_count; iter++) {
|
||||
prev_time = time;
|
||||
/* Gives us good precision at center and ensure we cross at least one pixel per iteration. */
|
||||
time = 1.0 + iter + sqr((iter + noise) / sample_count) * ssray.max_time;
|
||||
float stride = time - prev_time;
|
||||
float lod = (log2(stride) - noise) / (1.0 + aoQuality);
|
||||
|
||||
vec2 uv = ssray.origin.xy + ssray.direction.xy * time;
|
||||
float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r;
|
||||
|
||||
if (depth == 1.0 && inverted == 0.0) {
|
||||
/* Skip background. This avoids issues with the thickness heuristic. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bias depth a bit to avoid self shadowing issues. */
|
||||
const float bias = 2.0 * 2.4e-7;
|
||||
depth += (inverted != 0.0) ? -bias : bias;
|
||||
|
@ -107,25 +119,16 @@ float search_horizon(vec3 vI,
|
|||
float s_h = dot(vI, omega_s / len);
|
||||
/* Blend weight to fade artifacts. */
|
||||
float dist_ratio = abs(len) / radius;
|
||||
/* TODO(fclem) parameter. */
|
||||
float dist_fac = sqr(saturate(dist_ratio * 2.0 - 1.0));
|
||||
/* Sphere falloff. */
|
||||
float dist_fac = sqr(saturate(dist_ratio));
|
||||
/* Unbiased, gives too much hard cut behind objects */
|
||||
// float dist_fac = step(0.999, dist_ratio);
|
||||
|
||||
/* Thickness heuristic (Eq. 9). */
|
||||
if (inverted != 0.0) {
|
||||
h = min(h, s_h);
|
||||
}
|
||||
else {
|
||||
/* TODO This need to take the stride distance into account. Now it works because stride is
|
||||
* constant. */
|
||||
if (s_h < h) {
|
||||
/* TODO(fclem) parameter. */
|
||||
const float thickness_fac = 0.2;
|
||||
s_h = mix(h, s_h, thickness_fac);
|
||||
}
|
||||
else {
|
||||
s_h = max(h, s_h);
|
||||
}
|
||||
h = mix(s_h, h, dist_fac);
|
||||
h = mix(max(h, s_h), h, dist_fac);
|
||||
}
|
||||
}
|
||||
return fast_acos(h);
|
||||
|
@ -150,22 +153,22 @@ OcclusionData occlusion_search(
|
|||
NO_OCCLUSION_DATA;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
/* View > NDC > Uv space. */
|
||||
vec2 uv_dir = dir * area * 0.5;
|
||||
/* Offset the start one pixel to avoid self shadowing. */
|
||||
/* TODO(fclem) Using DDA line algo should fix this. */
|
||||
vec2 px_dir = uv_dir * textureSize(depth_tx, 0);
|
||||
float max_px_dir = max_v2(abs(px_dir));
|
||||
vec2 uv_ofs = (px_dir / max_px_dir) / textureSize(depth_tx, 0);
|
||||
/* No need to trace more. */
|
||||
uv_dir -= uv_ofs;
|
||||
Ray ray;
|
||||
ray.origin = vP;
|
||||
ray.direction = vec3(dir * radius, 0.0);
|
||||
|
||||
ScreenSpaceRay ssray;
|
||||
|
||||
ssray = raytrace_screenspace_ray_create(ray);
|
||||
data.horizons[0 + i * 2] = search_horizon(
|
||||
vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count);
|
||||
|
||||
ray.direction = -ray.direction;
|
||||
|
||||
ssray = raytrace_screenspace_ray_create(ray);
|
||||
data.horizons[1 + i * 2] = -search_horizon(
|
||||
vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count);
|
||||
|
||||
if (max_px_dir > 1.0) {
|
||||
data.horizons[0 + i * 2] = search_horizon(
|
||||
vI, vP, noise.y, uv + uv_ofs, uv_dir, depth_tx, inverted, radius, dir_sample_count);
|
||||
data.horizons[1 + i * 2] = -search_horizon(
|
||||
vI, vP, noise.y, uv - uv_ofs, -uv_dir, depth_tx, inverted, radius, dir_sample_count);
|
||||
}
|
||||
/* Rotate 90 degrees. */
|
||||
dir = vec2(-dir.y, dir.x);
|
||||
}
|
||||
|
@ -388,7 +391,7 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion)
|
|||
data = unpack_occlusion_data(texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0));
|
||||
}
|
||||
#else
|
||||
/* For blended surfaces and */
|
||||
/* For blended surfaces. */
|
||||
data = occlusion_search(vP, maxzBuffer, aoDistance, 0.0, 8.0);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -65,8 +65,6 @@ void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray)
|
|||
/* Clipping to frustum sides. */
|
||||
float clip_dist = line_unit_box_intersect_dist(ray.origin.xyz, ray.direction.xyz);
|
||||
ray.max_time = min(ray.max_time, clip_dist);
|
||||
/* Avoid no iteration. */
|
||||
ray.max_time = max(ray.max_time, 1.1);
|
||||
/* Convert to texture coords [0..1] range. */
|
||||
ray.origin = ray.origin * 0.5 + 0.5;
|
||||
ray.direction *= 0.5;
|
||||
|
@ -122,6 +120,8 @@ bool raytrace(Ray ray,
|
|||
}
|
||||
|
||||
ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray, params.thickness);
|
||||
/* Avoid no iteration. */
|
||||
ssray.max_time = max(ssray.max_time, 1.1);
|
||||
|
||||
float prev_delta = 0.0, prev_time = 0.0;
|
||||
float depth_sample = get_depth_from_view_z(ray.origin.z);
|
||||
|
@ -173,6 +173,8 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out
|
|||
}
|
||||
|
||||
ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray);
|
||||
/* Avoid no iteration. */
|
||||
ssray.max_time = max(ssray.max_time, 1.1);
|
||||
|
||||
/* Planar Reflections have X mirrored. */
|
||||
ssray.origin.x = 1.0 - ssray.origin.x;
|
||||
|
|
Loading…
Reference in New Issue