diff options
Diffstat (limited to 'source')
6 files changed, 163 insertions, 84 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 0c5f6ee9f4d..a077f6833d2 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -58,6 +58,15 @@ typedef struct EEVEE_LightProbeData { short probe_id, shadow_id; } EEVEE_LightProbeData; +/* SSR shader variations */ +enum { + SSR_RESOLVE = (1 << 0), + SSR_TWO_HIT = (1 << 1), + SSR_FULL_TRACE = (1 << 2), + SSR_NORMALIZE = (1 << 3), + SSR_MAX_SHADER = (1 << 4), +}; + static struct { /* Downsample Depth */ struct GPUShader *minz_downlevel_sh; @@ -85,12 +94,7 @@ static struct { struct GPUShader *volumetric_upsample_sh; /* Screen Space Reflection */ - struct GPUShader *ssr_raytrace_sh; - struct GPUShader *ssr_raytrace_full_sh; - struct GPUShader *ssr_resolve_sh; - struct GPUShader *ssr_resolve_full_sh; - struct GPUShader *ssr_resolve_norm_sh; - struct GPUShader *ssr_resolve_full_norm_sh; + struct GPUShader *ssr_sh[SSR_MAX_SHADER]; /* Simple Downsample */ struct GPUShader *downsample_sh; @@ -171,6 +175,48 @@ static void eevee_motion_blur_camera_get_matrix_at_time( mul_m4_m4m4(r_mat, params.winmat, obmat); } +static struct GPUShader *eevee_effects_ssr_shader_get(int options) +{ + if (e_data.ssr_sh[options] == NULL) { + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl); + char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + DynStr *ds_defines = BLI_dynstr_new(); + BLI_dynstr_appendf(ds_defines, SHADER_DEFINES); + if (options & SSR_RESOLVE) { + BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n"); + } + else { + BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n"); + } + if (options & SSR_TWO_HIT) { + BLI_dynstr_appendf(ds_defines, "#define TWO_HIT\n"); + } + if (options & SSR_FULL_TRACE) { + BLI_dynstr_appendf(ds_defines, "#define FULLRES\n"); + } + if (options & SSR_NORMALIZE) { + BLI_dynstr_appendf(ds_defines, "#define USE_NORMALIZATION\n"); + } + char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines); + BLI_dynstr_free(ds_defines); + + e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str); + + MEM_freeN(ssr_shader_str); + MEM_freeN(ssr_define_str); + } + + return e_data.ssr_sh[options]; +} + void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -190,30 +236,6 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) /* Shaders */ if (!e_data.motion_blur_sh) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl); - char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.ssr_raytrace_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RAYTRACE\n"); - e_data.ssr_raytrace_full_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RAYTRACE\n" - "#define FULLRES\n"); - e_data.ssr_resolve_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n"); - e_data.ssr_resolve_norm_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n" - "#define USE_NORMALIZATION\n"); - e_data.ssr_resolve_full_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n" - "#define FULLRES\n"); - e_data.ssr_resolve_full_norm_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n" - "#define USE_NORMALIZATION\n" - "#define FULLRES\n"); - - 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"); @@ -555,6 +577,7 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) /* Enable double buffering to be able to read previous frame color */ effects->enabled_effects |= EFFECT_DOUBLE_BUFFER; + effects->ssr_use_two_hit = BKE_collection_engine_property_value_get_bool(props, "ssr_two_rays"); effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight"); effects->ssr_stride = (float)BKE_collection_engine_property_value_get_int(props, "ssr_stride"); @@ -563,7 +586,6 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; - const bool record_two_hit = false; const bool high_qual_input = true; /* TODO dither low quality input */ /* MRT for the shading pass in order to output needed data for the SSR pass. */ @@ -587,8 +609,8 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) /* Raytracing output */ /* TODO try integer format for hit coord to increase precision */ - DRWFboTexture tex_output[2] = {{&stl->g_data->ssr_hit_output, (record_two_hit) ? DRW_TEX_RGBA_16 : DRW_TEX_RG_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_pdf_output, (record_two_hit) ? DRW_TEX_RG_16 : DRW_TEX_R_16, DRW_TEX_TEMP}}; + DRWFboTexture tex_output[2] = {{&stl->g_data->ssr_hit_output, (effects->ssr_use_two_hit) ? DRW_TEX_RGBA_16 : DRW_TEX_RG_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_pdf_output, (effects->ssr_use_two_hit) ? DRW_TEX_RG_16 : DRW_TEX_R_16, DRW_TEX_TEMP}}; DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, 2); @@ -626,9 +648,6 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex_double_buffer, 1); - - copy_m4_m4(stl->g_data->prev_persmat, stl->g_data->next_persmat); - DRW_viewport_matrix_get(stl->g_data->next_persmat, DRW_MAT_PERS); } else { /* Cleanup to release memory */ @@ -724,14 +743,13 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) } if ((effects->enabled_effects & EFFECT_SSR) != 0) { - struct GPUShader *trace_shader = (effects->reflection_trace_full) ? e_data.ssr_raytrace_full_sh : e_data.ssr_raytrace_sh; - struct GPUShader *resolve_shader = NULL; - if (effects->ssr_use_normalization) { - resolve_shader = (effects->reflection_trace_full) ? e_data.ssr_resolve_full_norm_sh : e_data.ssr_resolve_norm_sh; - } - else { - resolve_shader = (effects->reflection_trace_full) ? e_data.ssr_resolve_full_sh : e_data.ssr_resolve_sh; - } + int options = 0; + options |= (effects->ssr_use_two_hit) ? SSR_TWO_HIT : 0; + options |= (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; + options |= (effects->ssr_use_normalization) ? SSR_NORMALIZE : 0; + + struct GPUShader *trace_shader = eevee_effects_ssr_shader_get(options); + struct GPUShader *resolve_shader = eevee_effects_ssr_shader_get(SSR_RESOLVE | options); psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); @@ -1230,22 +1248,21 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) DRW_viewport_request_redraw(); } + /* Record pers matrix for the next frame. */ + DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS); + /* Update double buffer status if render mode. */ if (DRW_state_is_image_render()) { stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL); - DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS); } } void EEVEE_effects_free(void) { + for (int i = 0; i < SSR_MAX_SHADER; ++i) { + DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]); + } DRW_SHADER_FREE_SAFE(e_data.downsample_sh); - DRW_SHADER_FREE_SAFE(e_data.ssr_raytrace_sh); - DRW_SHADER_FREE_SAFE(e_data.ssr_raytrace_full_sh); - DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_sh); - DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_full_sh); - DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_norm_sh); - DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_full_norm_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_upsample_sh); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 2e0dce656da..578068b98e4 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -218,6 +218,7 @@ static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPr props->subtype == IDP_GROUP_SUB_ENGINE_RENDER); BKE_collection_engine_property_add_bool(props, "ssr_enable", false); + BKE_collection_engine_property_add_bool(props, "ssr_two_rays", false); BKE_collection_engine_property_add_bool(props, "ssr_normalize_weight", false); BKE_collection_engine_property_add_bool(props, "ssr_halfres", true); BKE_collection_engine_property_add_int(props, "ssr_stride", 16); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 824c338b927..5dda9b088e3 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -319,6 +319,7 @@ typedef struct EEVEE_EffectsInfo { /* SSR */ bool use_ssr; bool reflection_trace_full; + bool ssr_use_two_hit; bool ssr_use_normalization; float ssr_border_fac; float ssr_stride; @@ -466,7 +467,6 @@ typedef struct EEVEE_PrivateData { /* For double buffering */ bool valid_double_buffer; float prev_persmat[4][4]; - float next_persmat[4][4]; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ 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 b61b191c2d1..268afa1e373 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -72,6 +72,10 @@ void main() 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 */ @@ -89,19 +93,35 @@ void main() /* 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; @@ -109,8 +129,20 @@ void main() 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 } #else /* STEP_RESOLVE */ @@ -222,6 +254,45 @@ float view_facing_mask(vec3 V, vec3 R) return smoothstep(0.95, 0.80, dot(V, R)); } +vec4 get_ssr_sample( + vec2 hit_co, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared, + float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel, + out float weight) +{ + /* Reconstruct ray */ + float hit_depth = textureLod(depthBuffer, hit_co, 0.0).r; + vec3 hit_pos = get_world_space_from_depth(hit_co, hit_depth); + + /* 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 */ + 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); + + 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; + + weight = step(0.001, pdf) * bsdf / pdf; +#else + weight = 1.0; +#endif + + vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb ; + + /* Firefly removal */ + sample /= 1.0 + brightness(sample); + + float mask = screen_border_mask(ref_uvs, hit_pos); + mask *= view_facing_mask(V, N); + + /* Check if there was a hit */ + return vec4(sample, mask) * weight * step(0.0, hit_co.x); +} #define NUM_NEIGHBORS 9 @@ -280,42 +351,24 @@ void main() for (int i = 0; i < NUM_NEIGHBORS; i++) { ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor; - 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); - - /* 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 */ - 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); - - 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, pdf) * bsdf / pdf; +#ifdef TWO_HIT + vec4 hit_co = texelFetch(hitBuffer, target_texel, 0).rgba; #else - float weight = 1.0; + vec2 hit_co = texelFetch(hitBuffer, target_texel, 0).rg; #endif - vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb ; - - /* Firefly removal */ - sample /= 1.0 + brightness(sample); - - float mask = screen_border_mask(ref_uvs, hit_pos); - mask *= view_facing_mask(V, N); + 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; - /* Check if there was a hit */ - ssr_accum += vec4(sample, mask) * weight * step(0.0, hit_co.x); +#ifdef TWO_HIT + ssr_accum += get_ssr_sample(hit_co.zw, worldPosition, N, V, + roughnessSquared, cone_tan, source_uvs, + texture_size, target_texel, weight); weight_acc += weight; +#endif } /* Compute SSR contribution */ diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index d0c60310a00..f017453bad0 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -113,7 +113,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_ float zmin = prev_zmax; zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w); prev_zmax = zmax; - swapIfBigger(zmin, zmax); /* ??? why don't we need this ??? */ + swapIfBigger(zmin, zmax); float vmax = get_view_z_from_depth(raw_depth); float vmin = vmax - ssrThickness; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 90dab17069e..a3983290236 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2623,6 +2623,7 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_shadows) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_shadow_samples) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_colored_transmittance) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable) +RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_two_rays) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_normalize_weight) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_stride) @@ -6197,6 +6198,13 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + prop = RNA_def_property(srna, "ssr_two_rays", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_two_rays_get", + "rna_LayerEngineSettings_Eevee_ssr_two_rays_set"); + RNA_def_property_ui_text(prop, "Double Trace", "Raytrace two rays instead of just one"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + prop = RNA_def_property(srna, "ssr_normalize_weight", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_normalize_weight_get", "rna_LayerEngineSettings_Eevee_ssr_normalize_weight_set"); |