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>2017-07-24 12:18:11 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-07-24 16:36:37 +0300
commit27dd82a951776a6a322a1009667a6cc6f4331b01 (patch)
tree5f3cd8f005851389b2b3a5c503cc4e867d36a696 /source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
parent7585c8272201856e8504a93b435d3bed3476b98e (diff)
Eevee: SSR: Refactor multiple rays. Plus other changes...
-Allow a maximum of 4 rays per trace pixel. -Removes parameter Normalize: use normalization all the time now. -Add firefly clamp slider.
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl227
1 files changed, 96 insertions, 131 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
index 268afa1e373..7b516f27ec9 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -1,9 +1,14 @@
+/* Based on Stochastic Screen Space Reflections
+ * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */
+
#ifndef UTIL_TEX
#define UTIL_TEX
uniform sampler2DArray utilTex;
#endif /* UTIL_TEX */
+uniform int rayCount;
+
#define BRDF_BIAS 0.7
vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf)
@@ -15,6 +20,7 @@ vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf)
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, BRDF_BIAS);
+ /* TODO distribution of visible normals */
vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
pdf = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */
return reflect(-V, H);
@@ -28,8 +34,34 @@ uniform sampler2D depthBuffer;
uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
-layout(location = 0) out vec4 hitData;
-layout(location = 1) out vec4 pdfData;
+uniform mat4 ViewProjectionMatrix;
+
+layout(location = 0) out vec4 hitData0;
+layout(location = 1) out vec4 hitData1;
+layout(location = 2) out vec4 hitData2;
+layout(location = 3) out vec4 hitData3;
+
+bool has_hit_backface(vec3 hit_pos, vec3 R, vec3 V)
+{
+ vec2 hit_co = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5;
+ vec3 hit_N = normal_decode(textureLod(normalBuffer, hit_co, 0.0).rg, V);
+ return (dot(-R, hit_N) < 0.0);
+}
+
+vec4 do_ssr(sampler2D depthBuffer, vec3 V, vec3 N, vec3 viewPosition, float a2, vec3 rand)
+{
+ float pdf;
+ vec3 R = generate_ray(V, N, a2, rand, pdf);
+
+ float hit_dist = raycast(depthBuffer, viewPosition, R, rand.x);
+ vec3 hit_pos = viewPosition + R * abs(hit_dist);
+
+ if (has_hit_backface(hit_pos, R, V) || (hit_dist <= 0.0)) {
+ hit_pos.z *= -1.0;
+ }
+
+ return vec4(hit_pos, pdf);
+}
void main()
{
@@ -68,81 +100,13 @@ void main()
float roughnessSquared = max(1e-3, roughness * roughness);
float a2 = roughnessSquared * roughnessSquared;
- /* Generate Ray */
- float pdf;
vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba;
- vec3 R = generate_ray(V, N, a2, rand, pdf);
-#ifdef TWO_HIT
- float pdf2;
- vec3 R2 = generate_ray(V, N, a2, rand * vec3(1.0, -1.0, -1.0), pdf2);
-#endif
-
- /* Search for the planar reflection affecting this pixel */
- /* If no planar is found, fallback to screen space */
-
- /* Raycast over planar reflection */
- /* Potentially lots of time waisted here for pixels
- * that does not have planar reflections. TODO Profile it. */
- /* TODO: Idea, rasterize boxes around planar
- * reflection volumes (frontface culling to avoid overdraw)
- * and do the raycasting, discard pixel that are not in influence.
- * Add stencil test to discard the main SSR.
- * Cons: - Potentially raytrace multiple times
- * if Planar Influence overlaps. */
- //float hit_dist = raycast(depthBuffer, W, R);
-
- /* Raycast over screen */
- float hit_dist = -1.0;
-#ifdef TWO_HIT
- float hit_dist2 = -1.0;
-#endif
- /* Only raytrace if ray is above the surface normal */
- /* Note : this still fails in some cases like with normal map.
- * We should check against the geometric normal but we don't have it at this stage. */
- if (dot(R, N) > 0.0001) {
- hit_dist = raycast(depthBuffer, viewPosition, R, rand.x);
- }
-#ifdef TWO_HIT
- /* TODO do double raytrace at the same time */
- if (dot(R2, N) > 0.0001) {
- hit_dist2 = raycast(depthBuffer, viewPosition, R2, rand.x);
- }
-#endif
-
- /* TODO Do reprojection here */
- vec2 hit_co = project_point(ProjectionMatrix, viewPosition + R * hit_dist).xy * 0.5 + 0.5;
-#ifdef TWO_HIT
- vec2 hit_co2 = project_point(ProjectionMatrix, viewPosition + R2 * hit_dist2).xy * 0.5 + 0.5;
-#endif
-
- /* Check if has hit a backface */
- vec3 hit_N = normal_decode(textureLod(normalBuffer, hit_co, 0.0).rg, V);
- hit_dist *= step(0.0, dot(-R, hit_N));
-#ifdef TWO_HIT
- hit_N = normal_decode(textureLod(normalBuffer, hit_co2, 0.0).rg, V);
- hit_dist2 *= step(0.0, dot(-R2, hit_N));
-#endif
-
- if (hit_dist > 0.0) {
- hitData = hit_co.xyxy;
- }
- else {
- hitData = vec4(-1.0);
- }
-#ifdef TWO_HIT
- if (hit_dist2 > 0.0) {
- hitData.zw = hit_co2;
- }
- else {
- hitData.zw = vec2(-1.0);
- }
-#endif
-#ifdef TWO_HIT
- pdfData = vec4(pdf, pdf2, 0.0, 0.0);
-#else
- pdfData = vec4(pdf);
-#endif
+ /* TODO : Raytrace together if textureGather is supported. */
+ hitData0 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand);
+ if (rayCount > 1) hitData1 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0));
+ if (rayCount > 2) hitData2 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0));
+ if (rayCount > 3) hitData3 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0));
}
#else /* STEP_RESOLVE */
@@ -152,12 +116,15 @@ uniform sampler2D depthBuffer;
uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
-uniform sampler2D hitBuffer;
-uniform sampler2D pdfBuffer;
+uniform sampler2D hitBuffer0;
+uniform sampler2D hitBuffer1;
+uniform sampler2D hitBuffer2;
+uniform sampler2D hitBuffer3;
uniform int probe_count;
uniform float borderFadeFactor;
+uniform float fireflyFactor;
uniform mat4 ViewProjectionMatrix;
uniform mat4 PastViewProjectionMatrix;
@@ -218,19 +185,6 @@ float brightness(vec3 c)
return max(max(c.r, c.g), c.b);
}
-vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
-{
- /* TODO real motion vectors */
- /* Transform to viewspace */
- // vec4(get_view_space_from_depth(uvcoords, depth), 1.0);
- // vec4(get_view_space_from_depth(uvcoords, depth), 1.0);
-
- /* Reproject */
- // vec3 hit_reprojected = find_reflection_incident_point(cameraPos, hit, pos, N);
-
- return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
-}
-
float screen_border_mask(vec2 past_hit_co, vec3 hit)
{
/* Fade on current and past screen edges */
@@ -254,44 +208,51 @@ float view_facing_mask(vec3 V, vec3 R)
return smoothstep(0.95, 0.80, dot(V, R));
}
+vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
+{
+ /* TODO real reprojection with motion vectors, etc... */
+ return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
+}
+
vec4 get_ssr_sample(
- vec2 hit_co, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
+ sampler2D hitBuffer, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
- out float weight)
+ inout float weight_acc)
{
- /* Reconstruct ray */
- float hit_depth = textureLod(depthBuffer, hit_co, 0.0).r;
- vec3 hit_pos = get_world_space_from_depth(hit_co, hit_depth);
+ vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba;
+ bool has_hit = (hit_co_pdf.z < 0.0);
+ hit_co_pdf.z = -abs(hit_co_pdf.z);
- /* Find hit position in previous frame */
+ /* Hit position in world space. */
+ vec3 hit_pos = (ViewMatrixInverse * vec4(hit_co_pdf.xyz, 1.0)).xyz;
+
+ /* Find hit position in previous frame. */
vec2 ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N);
- /* Estimate a cone footprint to sample a corresponding mipmap level */
- /* compute cone footprint Using UV distance because we are using screen space filtering */
+ /* Estimate a cone footprint to sample a corresponding mipmap level. */
+ /* Compute cone footprint Using UV distance because we are using screen space filtering. */
float cone_footprint = 1.5 * cone_tan * distance(ref_uvs, source_uvs);
float mip = BRDF_BIAS * clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, MAX_MIP);
+ /* Slide 54 */
vec3 L = normalize(hit_pos - worldPosition);
-#ifdef USE_NORMALIZATION
- /* Evaluate BSDF */
float bsdf = bsdf_ggx(N, L, V, roughnessSquared);
- float pdf = texelFetch(pdfBuffer, target_texel, 0).r;
+ float weight = step(0.001, hit_co_pdf.w) * bsdf / hit_co_pdf.w;
+ weight_acc += weight;
- weight = step(0.001, pdf) * bsdf / pdf;
-#else
- weight = 1.0;
-#endif
+ vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb;
- vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb ;
+ /* Do not add light if ray has failed. */
+ sample *= float(has_hit);
/* Firefly removal */
- sample /= 1.0 + brightness(sample);
+ sample /= 1.0 + fireflyFactor * brightness(sample);
float mask = screen_border_mask(ref_uvs, hit_pos);
mask *= view_facing_mask(V, N);
+ mask *= float(has_hit);
- /* Check if there was a hit */
- return vec4(sample, mask) * weight * step(0.0, hit_co.x);
+ return vec4(sample, mask) * weight;
}
#define NUM_NEIGHBORS 9
@@ -341,34 +302,40 @@ void main()
float weight_acc = 0.0;
const ivec2 neighbors[9] = ivec2[9](
ivec2(0, 0),
- ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1),
- ivec2(-1, 0), ivec2(1, 0),
- ivec2(-1, -1), ivec2(0, -1), ivec2(1, -1)
+
+ ivec2(0, 1),
+ ivec2(-1, -1), ivec2(1, -1),
+
+ ivec2(-1, 1), ivec2(1, 1),
+ ivec2(0, -1),
+
+ ivec2(-1, 0), ivec2(1, 0)
);
ivec2 invert_neighbor;
invert_neighbor.x = ((fullres_texel.x & 0x1) == 0) ? 1 : -1;
invert_neighbor.y = ((fullres_texel.y & 0x1) == 0) ? 1 : -1;
+
for (int i = 0; i < NUM_NEIGHBORS; i++) {
ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor;
-#ifdef TWO_HIT
- vec4 hit_co = texelFetch(hitBuffer, target_texel, 0).rgba;
-#else
- vec2 hit_co = texelFetch(hitBuffer, target_texel, 0).rg;
-#endif
-
- float weight;
- ssr_accum += get_ssr_sample(hit_co.xy, worldPosition, N, V,
- roughnessSquared, cone_tan, source_uvs,
- texture_size, target_texel, weight);
- weight_acc += weight;
-
-#ifdef TWO_HIT
- ssr_accum += get_ssr_sample(hit_co.zw, worldPosition, N, V,
+ ssr_accum += get_ssr_sample(hitBuffer0, worldPosition, N, V,
roughnessSquared, cone_tan, source_uvs,
- texture_size, target_texel, weight);
- weight_acc += weight;
-#endif
+ texture_size, target_texel, weight_acc);
+ if (rayCount > 1) {
+ ssr_accum += get_ssr_sample(hitBuffer1, worldPosition, N, V,
+ roughnessSquared, cone_tan, source_uvs,
+ texture_size, target_texel, weight_acc);
+ }
+ if (rayCount > 2) {
+ ssr_accum += get_ssr_sample(hitBuffer2, worldPosition, N, V,
+ roughnessSquared, cone_tan, source_uvs,
+ texture_size, target_texel, weight_acc);
+ }
+ if (rayCount > 3) {
+ ssr_accum += get_ssr_sample(hitBuffer3, worldPosition, N, V,
+ roughnessSquared, cone_tan, source_uvs,
+ texture_size, target_texel, weight_acc);
+ }
}
/* Compute SSR contribution */
@@ -385,8 +352,6 @@ void main()
}
fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
- // vec2 _uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
- // fragColor = vec4(textureLod(colorBuffer, _uvs, roughness * MAX_MIP).rgb, 1.0);
}
#endif