Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2021-03-08 19:12:25 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-03-08 19:25:38 +0300
commit0983e66e03001d9f38075d3a9ee8fcaa7966a7d2 (patch)
tree88080b965d73d3cfb3c5f5809a35f97f77488966 /source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
parent5db5966cdb61d5711d5c737fd8d000c69be9cf5e (diff)
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.
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl83
1 files changed, 43 insertions, 40 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 0b01b186b1b..689f99edad9 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -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;
-
- 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);
- }
+ 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);
+
/* 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