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-20 19:40:23 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-07-24 16:28:27 +0300
commitf1bf9d6bfb9edf261586a3907d7197a805ce8c3b (patch)
tree845c757c881cfa95d4be0d2a6c1a9b4e3e19d07f /source/blender
parent09413fad12c92fcd6c3410eadcdfc8f91bc028ef (diff)
Eevee: SSR: Add mipmap filtering and bias to reduce noise.
Also fix the roughness factors.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c35
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h2
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl16
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl15
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl80
7 files changed, 126 insertions, 25 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 3ebdea06093..4098cfe696e 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -138,6 +138,7 @@ data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 6414ef8ff32..e4c4cb5d790 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -84,7 +84,10 @@ static struct {
struct GPUShader *ssr_raytrace_sh;
struct GPUShader *ssr_resolve_sh;
+ struct GPUShader *downsample_sh;
+
struct GPUTexture *depth_src;
+ struct GPUTexture *color_src;
float pixelprojmat[4][4];
} e_data = {NULL}; /* Engine data */
@@ -99,6 +102,7 @@ extern char datatoc_effect_bloom_frag_glsl[];
extern char datatoc_effect_dof_vert_glsl[];
extern char datatoc_effect_dof_geom_glsl[];
extern char datatoc_effect_dof_frag_glsl[];
+extern char datatoc_effect_downsample_frag_glsl[];
extern char datatoc_lightprobe_lib_glsl[];
extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_tonemap_frag_glsl[];
@@ -192,6 +196,8 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
MEM_freeN(ssr_shader_str);
+ e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
+
e_data.volumetric_upsample_sh = DRW_shader_create_fullscreen(datatoc_volumetric_frag_glsl, "#define STEP_UPSAMPLE\n");
e_data.minmaxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, NULL);
@@ -578,7 +584,7 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
/* Setup double buffer so we can access last frame as it was before post processes */
if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) {
- DRWFboTexture tex_double_buffer = {&txl->color_double_buffer, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+ DRWFboTexture tex_double_buffer = {&txl->color_double_buffer, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type,
(int)viewport_size[0], (int)viewport_size[1],
@@ -711,6 +717,13 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
{
+ psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps);
+ DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
psl->minmaxz_downlevel = DRW_pass_create("HiZ Down Level", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.minmaxz_downlevel_sh, psl->minmaxz_downlevel);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minmaxz);
@@ -833,6 +846,12 @@ static void minmax_downsample_cb(void *vedata, int UNUSED(level))
DRW_draw_pass(psl->minmaxz_downlevel);
}
+static void simple_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->color_downsample_ps);
+}
+
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src)
{
EEVEE_PassList *psl = vedata->psl;
@@ -851,6 +870,17 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src)
DRW_framebuffer_recursive_downsample(fbl->minmaxz_fb, stl->g_data->minmaxz, 6, &minmax_downsample_cb, vedata);
}
+/**
+ * Simple downsampling algorithm. Reconstruct mip chain up to mip level.
+ **/
+void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, GPUTexture *texture_src, int level)
+{
+ e_data.color_src = texture_src;
+
+ /* Create lower levels */
+ DRW_framebuffer_recursive_downsample(fb_src, texture_src, level, &simple_downsample_cb, vedata);
+}
+
void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
@@ -902,6 +932,8 @@ void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *veda
if ((effects->enabled_effects & EFFECT_SSR) != 0 && stl->g_data->valid_double_buffer) {
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_downsample_buffer(vedata, fbl->minmaxz_fb, txl->color_double_buffer, 5);
+
/* Raytrace at halfres. */
e_data.depth_src = dtxl->depth;
// e_data.depth_src = stl->g_data->minmaxz;
@@ -1078,6 +1110,7 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
void EEVEE_effects_free(void)
{
+ DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
DRW_SHADER_FREE_SAFE(e_data.ssr_raytrace_sh);
DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_sh);
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 59f2613dd06..4ee3dee655f 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -56,7 +56,7 @@ static void EEVEE_engine_init(void *ved)
stl->g_data->background_alpha = 1.0f;
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
- DRWFboTexture tex = {&txl->color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER};
+ DRWFboTexture tex = {&txl->color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
const float *viewport_size = DRW_viewport_size_get();
DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type,
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 015bc5b6a9e..f31f4f9fe6c 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -111,6 +111,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *volumetric_resolve_transmit_ps;
struct DRWPass *ssr_raytrace;
struct DRWPass *ssr_resolve;
+ struct DRWPass *color_downsample_ps;
struct DRWPass *depth_pass;
struct DRWPass *depth_pass_cull;
@@ -504,6 +505,7 @@ void EEVEE_lightprobes_free(void);
void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src);
+void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level);
void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_draw_effects(EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 059f0598156..e6cbcde77c7 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -374,6 +374,22 @@ void accumulate_light(vec3 light, float fac, inout vec4 accum)
accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a));
}
+/* ----------- Cone Apperture Approximation --------- */
+
+/* Return a fitted cone angle given the input roughness */
+float cone_cosine(float r)
+{
+ /* Using phong gloss
+ * roughness = sqrt(2/(gloss+2)) */
+ float gloss = -2 + 2 / (r * r);
+ /* Drobot 2014 in GPUPro5 */
+ // return cos(2.0 * sqrt(2.0 / (gloss + 2)));
+ /* Uludag 2014 in GPUPro5 */
+ // return pow(0.244, 1 / (gloss + 1));
+ /* Jimenez 2016 in Practical Realtime Strategies for Accurate Indirect Occlusion*/
+ return exp2(-3.32193 * r * r);
+}
+
/* --------- Closure ---------- */
#ifdef VOLUMETRICS
diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
new file mode 100644
index 00000000000..4a79fa908b1
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
@@ -0,0 +1,15 @@
+/**
+ * Simple downsample shader. Takes the average of the 4 texels of lower mip.
+ **/
+
+uniform sampler2D source;
+
+out vec4 FragColor;
+
+void main()
+{
+ /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
+ vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+
+ FragColor = texture(source, uvs);
+} \ No newline at end of file
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 7337ec792c9..4a1cea1338e 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -4,17 +4,25 @@
uniform sampler2DArray utilTex;
#endif /* UTIL_TEX */
-vec3 generate_ray(ivec2 pix, vec3 V, vec3 N, float roughnessSquared, out float pdf)
+#define BRDF_BIAS 0.7
+
+vec3 generate_ray(ivec2 pix, vec3 V, vec3 N, float a2, out float pdf)
{
float NH;
vec3 T, B;
make_orthonormal_basis(N, T, B); /* Generate tangent space */
vec3 rand = texelFetch(utilTex, ivec3(pix % LUT_SIZE, 2), 0).rba;
- vec3 H = sample_ggx(rand, roughnessSquared, N, T, B, NH); /* Microfacet normal */
- pdf = max(32e32, pdf_ggx_reflect(NH, roughnessSquared)); /* Theoretical limit of 10bit float (not in practice?) */
+
+ /* Importance sampling bias */
+ rand.x = mix(rand.x, 0.0, BRDF_BIAS);
+
+ 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);
}
+#define MAX_MIP 5.0
+
#ifdef STEP_RAYTRACE
uniform sampler2D depthBuffer;
@@ -44,11 +52,12 @@ void main()
/* Retrieve pixel data */
vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
float roughness = speccol_roughness.a;
- float roughnessSquared = roughness * roughness;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+ float a2 = roughnessSquared * roughnessSquared;
/* Generate Ray */
float pdf;
- vec3 R = generate_ray(halfres_texel, V, N, roughnessSquared, pdf);
+ vec3 R = generate_ray(halfres_texel, V, N, a2, pdf);
/* Search for the planar reflection affecting this pixel */
/* If no planar is found, fallback to screen space */
@@ -65,7 +74,11 @@ void main()
//float hit_dist = raycast(depthBuffer, W, R);
/* Raycast over screen */
- float hit_dist = raycast(depthBuffer, viewPosition, R);
+ float hit_dist = -1.0;
+ if (dot(R, N) > 0.0001) {
+ /* Only raytrace if ray is above the surface normal */
+ hit_dist = raycast(depthBuffer, viewPosition, R);
+ }
vec2 hit_co = project_point(ProjectionMatrix, viewPosition + R * hit_dist).xy * 0.5 + 0.5;
@@ -164,7 +177,7 @@ float screen_border_mask(vec2 past_hit_co, vec3 hit)
hit_co.zw = past_hit_co;
const float margin = 0.002;
- const float atten = 0.05 + margin; /* Screen percentage */
+ const float atten = 0.1 + 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);
@@ -179,7 +192,9 @@ void main()
{
ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
- vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
+ vec2 texture_size = vec2(textureSize(depthBuffer, 0));
+ vec2 uvs = gl_FragCoord.xy / texture_size;
+ vec3 rand = texelFetch(utilTex, ivec3(fullres_texel % LUT_SIZE, 2), 0).rba;
float depth = textureLod(depthBuffer, uvs, 0.0).r;
@@ -194,48 +209,67 @@ void main()
vec3 N = mat3(ViewMatrixInverse) * normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
float roughness = speccol_roughness.a;
- float roughnessSquared = roughness * roughness;
+ float roughnessSquared = max(1e-3, roughness * roughness);
vec4 spec_accum = vec4(0.0);
- /* Resolve SSR and compute contribution */
+ /* Resolve SSR */
+ float cone_cos = cone_cosine(roughness);
+ float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
+ cone_tan *= mix(saturate(dot(N, V) * 2.0), 1.0, sqrt(roughness)); /* Elongation fit */
- /* We generate the same rays that has been generated in the raycast step.
- * But we add this ray from our resolve pixel position, increassing accuracy. */
vec3 ssr_accum = vec3(0.0);
float weight_acc = 0.0;
- float mask = 0.0;
- const ivec2 neighbors[7] = ivec2[7](ivec2(0, 0), ivec2(2, 1), ivec2(-2, 1), ivec2(0, -2), ivec2(-2, -1), ivec2(2, -1), ivec2(0, 2));
- int invert_neighbor = ((((fullres_texel.x & 0x1) + (fullres_texel.y & 0x1)) & 0x1) == 0) ? 1 : -1;
+ float mask_acc = 0.0;
+ float dist_acc = 0.0;
+ float hit_acc = 0.0;
+ const ivec2 neighbors[4] = ivec2[4](ivec2(0, 0), ivec2(1, 1), ivec2(0, 1), 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;
float pdf = texelFetch(pdfBuffer, target_texel, 0).r;
/* Check if there was a hit */
- if (pdf != 0.0) {
+ if (pdf > 0.001) {
vec2 hit_co = texelFetch(hitBuffer, target_texel, 0).rg;
/* Reconstruct ray */
float hit_depth = textureLod(depthBuffer, hit_co, 0.0).r;
vec3 hit_pos = get_world_space_from_depth(hit_co, hit_depth);
+ /* Evaluate BSDF */
+ vec3 L = normalize(hit_pos - worldPosition);
+ float bsdf = bsdf_ggx(N, L, V, roughnessSquared);
+
/* Find hit position in previous frame */
vec2 ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N);
+ vec2 source_uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
- /* Evaluate BSDF */
- vec3 L = normalize(hit_pos - worldPosition);
- float bsdf = bsdf_ggx(N, L, V, max(1e-3, roughness));
+ /* 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 = 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);
- float weight = bsdf / max(1e-8, pdf);
- mask += screen_border_mask(ref_uvs, hit_pos);
- ssr_accum += textureLod(colorBuffer, ref_uvs, 0.0).rgb * weight;
+ float border_mask = screen_border_mask(ref_uvs, hit_pos);
+ float weight = border_mask * bsdf / max(1e-8, pdf);
+ ssr_accum += textureLod(colorBuffer, ref_uvs, mip).rgb * weight;
weight_acc += weight;
+ dist_acc += distance(hit_pos, worldPosition);
+ mask_acc += border_mask;
+ hit_acc += 1.0;
}
}
+ /* Compute SSR contribution */
if (weight_acc > 0.0) {
- accumulate_light(ssr_accum / weight_acc, mask / float(NUM_NEIGHBORS), spec_accum);
+ /* Fade intensity based on roughness and average distance to hit */
+ float fade = saturate(2.0 - roughness * 2.0); /* fade between 0.5 and 1.0 roughness */
+ fade *= mask_acc / hit_acc;
+ fade *= mask_acc / hit_acc;
+ accumulate_light(ssr_accum / weight_acc, fade, spec_accum);
}
/* If SSR contribution is not 1.0, blend with cubemaps */