Eevee: SSR: Add support for planar probes.
authorClément Foucault <foucault.clem@gmail.com>
Tue, 25 Jul 2017 17:03:07 +0000 (19:03 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Tue, 25 Jul 2017 20:07:35 +0000 (22:07 +0200)
This add the possibility to use planar probe informations to create SSR.
This has 2 advantages:
- Tracing is less expensive since the hit is found much quicker.
- We have much less artifact due to missing information.

There is still area for improvement.

source/blender/draw/engines/eevee/eevee_effects.c
source/blender/draw/engines/eevee/eevee_lightprobes.c
source/blender/draw/engines/eevee/eevee_materials.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl

index 0ddced10ae00a0f4c1630de552374080599edf66..95280c5f2063bb1d712051c0789c34160eed486b 100644 (file)
@@ -766,6 +766,9 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
                DRW_shgroup_uniform_vec2(grp, "ssrParameters", &effects->ssr_stride, 1);
                DRW_shgroup_uniform_mat4(grp, "PixelProjMatrix", (float *)&e_data.pixelprojmat);
                DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1);
+               DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1);
+               DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth);
+               DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
                DRW_shgroup_call_add(grp, quad, NULL);
 
                psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
@@ -777,6 +780,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
                DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color_double_buffer);
                DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat);
                DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2);
+               DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1);
                DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1);
                DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1);
                DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
index 151efefcda10fae4849744fd11b8faaed33ac260..869a9798ce2417a46cd0733ec0b94cc9dd2a71c7 100644 (file)
@@ -276,6 +276,7 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(ved
        if (!sldata->probes) {
                sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
                sldata->probes->specular_toggle = true;
+               sldata->probes->ssr_toggle = true;
                sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
                sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
                sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
@@ -962,6 +963,7 @@ static void render_scene_to_probe(
 
        /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
        sldata->probes->specular_toggle = false;
+       sldata->probes->ssr_toggle = false;
 
        /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */
        tmp_ao_dist = stl->effects->ao_dist;
@@ -1045,7 +1047,7 @@ static void render_scene_to_probe(
 }
 
 static void render_scene_to_planar(
-        EEVEE_Data *vedata, int layer,
+        EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, int layer,
         float (*viewmat)[4], float (*persmat)[4],
         float clip_plane[4])
 {
@@ -1066,6 +1068,9 @@ static void render_scene_to_planar(
 
        DRW_framebuffer_clear(false, true, false, NULL, 1.0);
 
+       /* Turn off ssr to avoid black specular */
+       sldata->probes->ssr_toggle = false;
+
        /* Avoid using the texture attached to framebuffer when rendering. */
        /* XXX */
        GPUTexture *tmp_planar_pool = txl->planar_pool;
@@ -1103,6 +1108,7 @@ static void render_scene_to_planar(
        DRW_state_clip_planes_reset();
 
        /* Restore */
+       sldata->probes->ssr_toggle = true;
        txl->planar_pool = tmp_planar_pool;
        txl->planar_depth = tmp_planar_depth;
        DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
@@ -1323,7 +1329,7 @@ update_planar:
                        int tmp_num_planar = pinfo->num_planar;
                        pinfo->num_planar = 0;
 
-                       render_scene_to_planar(vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
+                       render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
 
                        /* Restore */
                        pinfo->num_planar = tmp_num_planar;
@@ -1335,7 +1341,7 @@ update_planar:
 
        /* If there is at least one planar probe */
        if (pinfo->num_planar > 0) {
-               const int max_lod = 5;
+               const int max_lod = 9;
                DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
                /* For shading, save max level of the planar map */
                pinfo->lod_planar_max = (float)(max_lod);
index eae9331fedc5a5465a27d082a7c97e87518317d5..c1112eedf0d04ef3539c045c8b02887699dd85d3 100644 (file)
@@ -272,6 +272,7 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *
        DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1);
        DRW_shgroup_uniform_int(shgrp, "planar_count", &sldata->probes->num_planar, 1);
        DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 1);
+       DRW_shgroup_uniform_bool(shgrp, "ssrToggle", &sldata->probes->ssr_toggle, 1);
        DRW_shgroup_uniform_float(shgrp, "lodCubeMax", &sldata->probes->lod_cube_max, 1);
        DRW_shgroup_uniform_float(shgrp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1);
        DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
index 55fb550d94083beea6c1f3f928a0d9ffbbb9112f..0b1fc2f5dff51970bce658febc8ae68f881df98d 100644 (file)
@@ -299,6 +299,7 @@ typedef struct EEVEE_LightProbesInfo {
        int shres;
        int shnbr;
        bool specular_toggle;
+       bool ssr_toggle;
        /* List of probes in the scene. */
        /* XXX This is fragile, can get out of sync quickly. */
        struct Object *probes_cube_ref[MAX_PROBE];
index e6cbcde77c7da406dd6ca458cb54ccf3b844ccf4..99e2132277dfe2f4dddf4d1d9ec38199973e0fa0 100644 (file)
@@ -153,6 +153,12 @@ vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin,
        return lineorigin + linedirection * dist;
 }
 
+vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec4 plane)
+{
+       float dist = line_plane_intersect_dist(lineorigin, linedirection, plane);
+       return lineorigin + linedirection * dist;
+}
+
 float line_aligned_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
 {
        /* aligned plane normal */
index 7b516f27ec9fcbb5b880ff751df84cdde68aef2e..901d1fa4aeafb8b28bb365f82cf82f84272cea9c 100644 (file)
@@ -30,10 +30,11 @@ vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf)
 
 #ifdef STEP_RAYTRACE
 
-uniform sampler2D depthBuffer;
 uniform sampler2D normalBuffer;
 uniform sampler2D specroughBuffer;
 
+uniform int planar_count;
+
 uniform mat4 ViewProjectionMatrix;
 
 layout(location = 0) out vec4 hitData0;
@@ -48,14 +49,53 @@ bool has_hit_backface(vec3 hit_pos, vec3 R, vec3 V)
        return (dot(-R, hit_N) < 0.0);
 }
 
-vec4 do_ssr(sampler2D depthBuffer, vec3 V, vec3 N, vec3 viewPosition, float a2, vec3 rand)
+vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand)
+{
+       float pdf;
+       vec3 R = generate_ray(V, N, a2, rand, pdf);
+
+       R = reflect(R, planeNormal);
+       pdf *= -1.0; /* Tag as planar ray. */
+
+       /* If ray is bad (i.e. going below the plane) do not trace. */
+       if (dot(R, planeNormal) > 0.0) {
+               vec3 R = generate_ray(V, N, a2, rand, pdf);
+       }
+
+       float hit_dist;
+       if (abs(dot(-R, V)) < 0.9999) {
+               hit_dist = raycast(index, viewPosition, R, rand.x);
+       }
+       else {
+               float z = get_view_z_from_depth(texelFetch(planarDepth, ivec3(project_point(PixelProjMatrix, viewPosition).xy, index), 0).r);
+               hit_dist = (z - viewPosition.z) / R.z;
+       }
+
+       /* Since viewspace hit position can land behind the camera in this case,
+        * we save the reflected view position (visualize it as the hit position
+        * below the reflection plane). This way it's garanted that the hit will
+        * be in front of the camera. That let us tag the bad rays with a negative
+        * sign in the Z component. */
+       vec3 hit_pos = viewPosition + R * abs(hit_dist);
+
+       /* Ray did not hit anything. No backface test because it's not possible
+        * to hit a backface in this case. */
+       if (hit_dist <= 0.0) {
+               hit_pos.z *= -1.0;
+       }
+
+       return vec4(hit_pos, pdf);
+}
+
+vec4 do_ssr(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);
+       float hit_dist = raycast(-1, viewPosition, R, rand.x);
        vec3 hit_pos = viewPosition + R * abs(hit_dist);
 
+       /* Ray did not hit anything. Tag it as failled. */
        if (has_hit_backface(hit_pos, R, V) || (hit_dist <= 0.0)) {
                hit_pos.z *= -1.0;
        }
@@ -102,17 +142,41 @@ void main()
 
        vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba;
 
+       vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+       vec3 wN = mat3(ViewMatrixInverse) * N;
+
+       /* Planar Reflections */
+       for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) {
+               PlanarData pd = planars_data[i];
+
+               float fade = probe_attenuation_planar(pd, worldPosition, wN);
+
+               if (fade > 0.5) {
+                       /* Find view vector / reflection plane intersection. */
+                       /* TODO optimize, use view space for all. */
+                       vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
+                       tracePosition = transform_point(ViewMatrix, tracePosition);
+                       vec3 planeNormal = mat3(ViewMatrix) * pd.pl_normal;
+
+                       /* TODO : Raytrace together if textureGather is supported. */
+                       hitData0 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand);
+                       if (rayCount > 1) hitData1 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0));
+                       if (rayCount > 2) hitData2 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0,  1.0, -1.0));
+                       if (rayCount > 3) hitData3 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0,  1.0));
+                       return;
+               }
+       }
+
        /* 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));
+       hitData0 = do_ssr(V, N, viewPosition, a2, rand);
+       if (rayCount > 1) hitData1 = do_ssr(V, N, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0));
+       if (rayCount > 2) hitData2 = do_ssr(V, N, viewPosition, a2, rand.xzy * vec3(1.0,  1.0, -1.0));
+       if (rayCount > 3) hitData3 = do_ssr(V, N, viewPosition, a2, rand.xzy * vec3(1.0, -1.0,  1.0));
 }
 
 #else /* STEP_RESOLVE */
 
 uniform sampler2D colorBuffer; /* previous frame */
-uniform sampler2D depthBuffer;
 uniform sampler2D normalBuffer;
 uniform sampler2D specroughBuffer;
 
@@ -122,6 +186,7 @@ uniform sampler2D hitBuffer2;
 uniform sampler2D hitBuffer3;
 
 uniform int probe_count;
+uniform int planar_count;
 
 uniform float borderFadeFactor;
 uniform float fireflyFactor;
@@ -185,19 +250,13 @@ float brightness(vec3 c)
        return max(max(c.r, c.g), c.b);
 }
 
-float screen_border_mask(vec2 past_hit_co, vec3 hit)
+float screen_border_mask(vec2 hit_co)
 {
-       /* Fade on current and past screen edges */
-       vec4 hit_co = ViewProjectionMatrix * vec4(hit, 1.0);
-       hit_co.xy = (hit_co.xy / hit_co.w) * 0.5 + 0.5;
-       hit_co.zw = past_hit_co;
-
        const float margin = 0.003;
        float atten = borderFadeFactor + margin; /* Screen percentage */
        hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co));
-       vec2 atten_fac = min(hit_co.xy, hit_co.zw);
 
-       float screenfade = atten_fac.x * atten_fac.y;
+       float screenfade = hit_co.x * hit_co.y;
 
        return screenfade;
 }
@@ -215,32 +274,65 @@ vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
 }
 
 vec4 get_ssr_sample(
-        sampler2D hitBuffer, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
+        sampler2D hitBuffer, PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
         float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
         inout float weight_acc)
 {
        vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba;
        bool has_hit = (hit_co_pdf.z < 0.0);
+       bool is_planar = (hit_co_pdf.w < 0.0);
        hit_co_pdf.z = -abs(hit_co_pdf.z);
+       hit_co_pdf.w = abs(hit_co_pdf.w);
 
        /* 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);
+       vec3 hit_pos = transform_point(ViewMatrixInverse, hit_co_pdf.xyz);
+
+       vec2 ref_uvs;
+       vec3 L;
+       float mask = 1.0;
+       float cone_footprint;
+       if (is_planar) {
+               /* Reflect back the hit position to have it in non-reflected world space */
+               vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
+               vec3 hit_vec = hit_pos - trace_pos;
+               hit_vec = reflect(hit_vec, pd.pl_normal);
+               hit_pos = hit_vec + trace_pos;
+               L = normalize(hit_vec);
+               ref_uvs = project_point(ProjectionMatrix, hit_co_pdf.xyz).xy * 0.5 + 0.5;
+               vec2 uvs = gl_FragCoord.xy / texture_size;
+
+               /* Compute cone footprint in screen space. */
+               float homcoord = ProjectionMatrix[2][3] * hit_co_pdf.z + ProjectionMatrix[3][3];
+               cone_footprint = length(hit_vec) * cone_tan * ProjectionMatrix[0][0] / homcoord;
+       }
+       else {
+               /* Find hit position in previous frame. */
+               ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N);
+               L = normalize(hit_pos - worldPosition);
+               mask *= view_facing_mask(V, N);
+               mask *= screen_border_mask(source_uvs);
+
+               /* Compute cone footprint Using UV distance because we are using screen space filtering. */
+               cone_footprint = 1.5 * cone_tan * distance(ref_uvs, source_uvs);
+       }
+       mask *= screen_border_mask(ref_uvs);
+       mask *= float(has_hit);
 
        /* 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);
        float bsdf = bsdf_ggx(N, L, V, roughnessSquared);
        float weight = step(0.001, hit_co_pdf.w) * bsdf / hit_co_pdf.w;
        weight_acc += weight;
 
-       vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb;
+       vec3 sample;
+       if (is_planar) {
+               sample = textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb;
+       }
+       else {
+               sample = textureLod(colorBuffer, ref_uvs, mip).rgb;
+       }
 
        /* Do not add light if ray has failed. */
        sample *= float(has_hit);
@@ -248,10 +340,6 @@ vec4 get_ssr_sample(
        /* Firefly removal */
        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);
-
        return vec4(sample, mask) * weight;
 }
 
@@ -286,6 +374,20 @@ void main()
        if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
                discard;
 
+       /* Find Planar Reflections affecting this pixel */
+       PlanarData pd;
+       float planar_index;
+       for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) {
+               pd = planars_data[i];
+
+               float fade = probe_attenuation_planar(pd, worldPosition, N);
+
+               if (fade > 0.5) {
+                       planar_index = float(i);
+                       break;
+               }
+       }
+
        float roughness = speccol_roughness.a;
        float roughnessSquared = max(1e-3, roughness * roughness);
 
@@ -318,21 +420,21 @@ void main()
        for (int i = 0; i < NUM_NEIGHBORS; i++) {
                ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor;
 
-               ssr_accum += get_ssr_sample(hitBuffer0, worldPosition, N, V,
+               ssr_accum += get_ssr_sample(hitBuffer0, pd, planar_index, worldPosition, N, V,
                                            roughnessSquared, cone_tan, source_uvs,
                                            texture_size, target_texel, weight_acc);
                if (rayCount > 1) {
-                       ssr_accum += get_ssr_sample(hitBuffer1, worldPosition, N, V,
+                       ssr_accum += get_ssr_sample(hitBuffer1, pd, planar_index, 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,
+                       ssr_accum += get_ssr_sample(hitBuffer2, pd, planar_index, 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,
+                       ssr_accum += get_ssr_sample(hitBuffer3, pd, planar_index, worldPosition, N, V,
                                                    roughnessSquared, cone_tan, source_uvs,
                                                    texture_size, target_texel, weight_acc);
                }
index 196a9888665a9dfac72ffc27b23d7196be8860e9..154d48eb2479ce77671a3e93aa138ef4dadcb4e1 100644 (file)
@@ -164,16 +164,11 @@ vec3 probe_evaluate_world_spec(vec3 R, float roughness)
 
 vec3 probe_evaluate_planar(
         float id, PlanarData pd, vec3 W, vec3 N, vec3 V,
-        float rand, vec3 camera_pos, float roughness,
+        float rand, float roughness,
         inout float fade)
 {
-       /* Sample reflection depth. */
-       vec4 refco = pd.reflectionmat * vec4(W, 1.0);
-       refco.xy /= refco.w;
-
-       /* Find view vector / reflection plane intersection. (dist_to_plane is negative) */
-       float dist_to_plane = line_plane_intersect_dist(camera_pos, V, pd.pl_plane_eq);
-       vec3 point_on_plane = camera_pos + V * dist_to_plane;
+       /* Find view vector / reflection plane intersection. */
+       vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
 
        /* How far the pixel is from the plane. */
        float ref_depth = 1.0; /* TODO parameter */
@@ -187,7 +182,7 @@ vec3 probe_evaluate_planar(
        vec3 ref_pos = point_on_plane + proj_ref;
 
        /* Reproject to find texture coords. */
-       refco = pd.reflectionmat * vec4(ref_pos, 1.0);
+       vec4 refco = pd.reflectionmat * vec4(ref_pos, 1.0);
        refco.xy /= refco.w;
 
        /* Distance to roughness */
index fa70fb5590fad4138058383fb4b50d841c9144be..c2ef085ca019722e7f7b52b99f7fd5c3e52cfc15 100644 (file)
@@ -13,8 +13,9 @@ out vec4 FragColor;
 void main()
 {
        /* Reconstructing Target uvs like this avoid missing pixels */
-       vec2 uvs = floor(gl_FragCoord.xy) * 2.0 * texelSize + texelSize;
+       vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0).xy);
 
+#if 0 /* Slower and does not match the main framebuffer downsampling. */
        /* Downsample with a 4x4 box filter */
        vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1);
 
@@ -24,4 +25,7 @@ void main()
        FragColor += texture(source, vec3(uvs + d.zw, layer)).rgba;
 
        FragColor /= 4.0;
+#endif
+
+       FragColor = texture(source, vec3(uvs, layer));
 }
\ No newline at end of file
index 9a851ac6badc2f35cbd76e353a17bd93c05867b0..4a1778091f6b0534af44a3688e2f3cc578ec4f10 100644 (file)
@@ -5,6 +5,7 @@ uniform int grid_count;
 uniform int planar_count;
 
 uniform bool specToggle;
+uniform bool ssrToggle;
 
 #ifndef UTIL_TEX
 #define UTIL_TEX
@@ -90,7 +91,7 @@ vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao,
        vec4 spec_accum = vec4(0.0);
 
        /* SSR lobe is applied later in a defered style */
-       if (ssr_id != outputSsrId) {
+       if (!ssrToggle || ssr_id != outputSsrId) {
                /* Planar Reflections */
                for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
                        PlanarData pd = planars_data[i];
@@ -98,7 +99,7 @@ vec3 eevee_surface_lit(vec3 N, vec3 albedo, vec3 f0, float roughness, float ao,
                        float fade = probe_attenuation_planar(pd, worldPosition, N);
 
                        if (fade > 0.0) {
-                               vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
+                               vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, roughness, fade);
                                accumulate_light(spec, fade, spec_accum);
                        }
                }
@@ -237,12 +238,12 @@ vec3 eevee_surface_clearcoat_lit(
                float fade = probe_attenuation_planar(pd, worldPosition, worldNormal);
 
                if (fade > 0.0) {
-                       if (ssr_id != outputSsrId) {
-                               vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
+                       if (!ssrToggle || ssr_id != outputSsrId) {
+                               vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, roughness, fade);
                                accumulate_light(spec, fade, spec_accum);
                        }
 
-                       vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, rand.r, cameraPos, C_roughness, fade);
+                       vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, rand.r, C_roughness, fade);
                        accumulate_light(C_spec, fade, C_spec_accum);
                }
        }
@@ -258,7 +259,7 @@ vec3 eevee_surface_clearcoat_lit(
                float fade = probe_attenuation_cube(cd, worldPosition);
 
                if (fade > 0.0) {
-                       if (ssr_id != outputSsrId) {
+                       if (!ssrToggle || ssr_id != outputSsrId) {
                                vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness);
                                accumulate_light(spec, fade, spec_accum);
                        }
@@ -270,7 +271,7 @@ vec3 eevee_surface_clearcoat_lit(
 
        /* World Specular */
        if (spec_accum.a < 0.999) {
-               if (ssr_id != outputSsrId) {
+               if (!ssrToggle || ssr_id != outputSsrId) {
                        vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
                        accumulate_light(spec, 1.0, spec_accum);
                }
@@ -453,7 +454,7 @@ vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao, int ss
        /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
        vec4 spec_accum = vec4(0.0);
 
-       if (ssr_id != outputSsrId) {
+       if (!ssrToggle || ssr_id != outputSsrId) {
                /* Planar Reflections */
                for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) {
                        PlanarData pd = planars_data[i];
@@ -461,7 +462,7 @@ vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao, int ss
                        float fade = probe_attenuation_planar(pd, worldPosition, N);
 
                        if (fade > 0.0) {
-                               vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, cameraPos, roughness, fade);
+                               vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, rand.r, roughness, fade);
                                accumulate_light(spec, fade, spec_accum);
                        }
                }
index 421079c0bfab38d085463908d9d1b9399d66f5ad..b4ccb1ca052dbed2d4f1643d0dd341396103206e 100644 (file)
@@ -9,9 +9,22 @@
 uniform mat4 PixelProjMatrix; /* View > NDC > Texel : maps view coords to texel coord */
 uniform vec2 ssrParameters;
 
+uniform sampler2D depthBuffer;
+uniform sampler2DArray planarDepth;
+
 #define ssrStride     ssrParameters.x
 #define ssrThickness  ssrParameters.y
 
+float sample_depth(ivec2 hitpixel, int index)
+{
+       if (index > -1) {
+               return texelFetch(planarDepth, ivec3(hitpixel, index), 0).r;
+       }
+       else {
+               return texelFetch(depthBuffer, hitpixel, 0).r;
+       }
+}
+
 void swapIfBigger(inout float a, inout float b)
 {
        if (a > b) {
@@ -22,7 +35,7 @@ void swapIfBigger(inout float a, inout float b)
 }
 
 /* Return the length of the ray if there is a hit, and negate it if not hit occured */
-float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_jitter)
+float raycast(int index, vec3 ray_origin, vec3 ray_dir, float ray_jitter)
 {
        float near = get_view_z_from_depth(0.0); /* TODO optimize */
        float far = get_view_z_from_depth(1.0); /* TODO optimize */
@@ -60,7 +73,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
 
        /* If the line is degenerate, make it cover at least one pixel
         * to not have to handle zero-pixel extent as a special case later */
-       P1 += vec2((distance_squared(P0, P1) < 0.0001) ? 0.01 : 0.0);
+       P1 += vec2((distance_squared(P0, P1) < 0.001) ? 0.01 : 0.0);
 
        vec2 delta = P1 - P0;
 
@@ -101,10 +114,16 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
        float end = P1.x * step_sign;
 
        /* Initial offset */
-       pqk += dPQK * (0.01 + ray_jitter);
+       if (index > -1) {
+               pqk -= dPQK * ray_jitter;
+       }
+       else {
+               pqk += dPQK * (0.01 + ray_jitter);
+       }
 
        bool hit = false;
        float raw_depth;
+       float thickness = (index == -1) ? ssrThickness : 1e16;
        for (float hitstep = 0.0; hitstep < MAX_STEP && !hit; hitstep++) {
                /* Ray finished & no hit*/
                if ((pqk.x * step_sign) > end) break;
@@ -113,7 +132,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
                pqk += dPQK;
 
                ivec2 hitpixel = ivec2(permute ? pqk.yx : pqk.xy);
-               raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r;
+               raw_depth = sample_depth(hitpixel, index);
 
                float zmin = prev_zmax;
                zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
@@ -121,7 +140,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
                swapIfBigger(zmin, zmax);
 
                float vmax = get_view_z_from_depth(raw_depth);
-               float vmin = vmax - ssrThickness;
+               float vmin = vmax - thickness;
 
                /* Check if we are somewhere near the surface. */
                /* Note: we consider hitting the screen borders (raw_depth == 0.0)
@@ -146,7 +165,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
                        pqk += dPQK;
 
                        ivec2 hitpixel = ivec2(permute ? pqk.yx : pqk.xy);
-                       raw_depth = texelFetch(depth_texture, hitpixel, 0).r;
+                       raw_depth = sample_depth(hitpixel, index);
 
                        float zmin = prev_zmax;
                        zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
@@ -154,7 +173,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
                        swapIfBigger(zmin, zmax);
 
                        float vmax = get_view_z_from_depth(raw_depth);
-                       float vmin = vmax - ssrThickness;
+                       float vmin = vmax - thickness;
 
                        /* Check if we are somewhere near the surface. */
                        if (!((zmin > vmax) || (zmax < vmin)) || (raw_depth == 0.0)) {