diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-08-10 16:43:15 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-08-10 16:43:48 +0300 |
commit | 6e2f17ea02be5caa9eee8a68ccd558474030b29a (patch) | |
tree | 29584459e5306ede452923a4956b17ac85eacc3d | |
parent | 896154d15de716ef360d0187cb89f44102ac31ef (diff) |
Eevee: Refraction: Add "thickness" parameter.
This enables to fake a second refraction event. This is great to simulate thin planar objects such as glass panels.
6 files changed, 68 insertions, 43 deletions
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 02025f458e4..29cb2466ee5 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -1183,8 +1183,8 @@ class EEVEE_MATERIAL_PT_options(MaterialButtonsPanel, Panel): if mat.blend_method not in {"OPAQUE", "CLIP", "HASHED"}: layout.prop(mat, "transparent_hide_backside") - layout.prop(mat, "transparent_screen_refraction") - + layout.prop(mat, "use_screen_refraction") + layout.prop(mat, "refraction_depth") classes = ( diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index cf27cba0b1a..517d7780719 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -353,7 +353,7 @@ static char *eevee_get_volume_defines(int options) **/ static void add_standard_uniforms( DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, - int *ssr_id, float *refract_thickness) + int *ssr_id, float *refract_depth, bool use_ssrefraction) { if (ssr_id == NULL) { static int no_ssr = -1.0f; @@ -379,13 +379,15 @@ static void add_standard_uniforms( DRW_shgroup_uniform_buffer(shgrp, "shadowCubes", &sldata->shadow_depth_cube_pool); DRW_shgroup_uniform_buffer(shgrp, "shadowCascades", &sldata->shadow_depth_cascade_pool); DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); - if (vedata->stl->effects->use_ao || refract_thickness) { + if (refract_depth != NULL) { + DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); + } + if (vedata->stl->effects->use_ao || use_ssrefraction) { DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); } - if (refract_thickness) { + if (use_ssrefraction) { DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color); - DRW_shgroup_uniform_float(shgrp, "refractionThickness", refract_thickness, 1); DRW_shgroup_uniform_vec4(shgrp, "ssrParameters", &vedata->stl->effects->ssr_quality, 1); DRW_shgroup_uniform_float(shgrp, "borderFadeFactor", &vedata->stl->effects->ssr_border_fac, 1); DRW_shgroup_uniform_float(shgrp, "maxRoughness", &vedata->stl->effects->ssr_max_roughness, 1); @@ -733,7 +735,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( } DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL); + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false); return shgrp; } @@ -763,7 +765,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL); + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false); } return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); @@ -944,10 +946,10 @@ static void material_opaque( *shgrp = DRW_shgroup_material_create(*gpumat, use_refract ? psl->refract_pass : psl->material_pass); if (*shgrp) { - static int ssr_id; - static float refract_thickness = 0.0f; /* TODO Param */ - ssr_id = (stl->effects->use_ssr) ? 0 : -1; - add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, (use_refract) ? &refract_thickness : NULL); + static int no_ssr = -1; + static int first_ssr = 0; + int *ssr_id = (stl->effects->use_ssr && !use_refract) ? &first_ssr : &no_ssr; + add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract); } else { /* Shader failed : pink color */ @@ -1036,9 +1038,7 @@ static void material_transparent( *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); if (*shgrp) { static int ssr_id = -1; /* TODO transparent SSR */ - static float refract_thickness = 0.0f; /* TODO Param */ - add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, - (use_refract) ? &refract_thickness : NULL); + add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract); } else { /* Shader failed : pink color */ @@ -1272,7 +1272,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL); + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false); BLI_ghash_insert(material_hash, ma, shgrp); diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index b3559e3d366..4ee2e778c21 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -7,9 +7,7 @@ uniform int planar_count; uniform bool specToggle; uniform bool ssrToggle; -#ifdef USE_REFRACTION -uniform float refractionThickness; -#endif +uniform float refractionDepth; #ifndef UTIL_TEX #define UTIL_TEX @@ -551,7 +549,7 @@ vec3 eevee_surface_glossy_lit(vec3 N, vec3 f0, float roughness, float ao, int ss /* ----------- Transmission ----------- */ -vec3 eevee_surface_refraction(vec3 N, vec3 f0, float roughness, float ior, int ssr_id, out vec3 ssr_spec) +vec3 eevee_surface_refraction(vec3 N, vec3 f0, float roughness, float ior) { /* Zero length vectors cause issues, see: T51979. */ #if 0 @@ -581,16 +579,26 @@ vec3 eevee_surface_refraction(vec3 N, vec3 f0, float roughness, float ior, int s /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */ vec4 trans_accum = vec4(0.0); + /* Refract the view vector using the depth heuristic. + * Then later Refract a second time the already refracted + * ray using the inverse ior. */ + float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior; + vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V; + vec3 refr_pos = (refractionDepth > 0.0) ? line_plane_intersect(worldPosition, refr_V, worldPosition - N * refractionDepth, N) : worldPosition; + #ifdef USE_REFRACTION /* Screen Space Refraction */ if (ssrToggle && roughness < maxRoughness + 0.2) { vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; + /* Find approximated position of the 2nd refraction event. */ + vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition; + float ray_ofs = 1.0 / float(rayCount); - vec4 spec = screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand, 0.0); - if (rayCount > 1) spec += screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); - if (rayCount > 2) spec += screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); - if (rayCount > 3) spec += screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); + vec4 spec = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand, 0.0); + if (rayCount > 1) spec += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); + if (rayCount > 2) spec += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); + if (rayCount > 3) spec += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); spec /= float(rayCount); spec.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); accumulate_light(spec.rgb, spec.a, trans_accum); @@ -599,7 +607,7 @@ vec3 eevee_surface_refraction(vec3 N, vec3 f0, float roughness, float ior, int s /* Specular probes */ /* NOTE: This bias the IOR */ - vec3 spec_dir = get_specular_refraction_dominant_dir(N, V, roughness, ior); + vec3 refr_dir = get_specular_refraction_dominant_dir(N, refr_V, roughness, final_ior); /* Starts at 1 because 0 is world probe */ for (int i = 1; i < MAX_PROBE && i < probe_count && trans_accum.a < 0.999; ++i) { @@ -608,14 +616,14 @@ vec3 eevee_surface_refraction(vec3 N, vec3 f0, float roughness, float ior, int s float fade = probe_attenuation_cube(cd, worldPosition); if (fade > 0.0) { - vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughnessSquared); + vec3 spec = probe_evaluate_cube(float(i), cd, refr_pos, refr_dir, roughnessSquared); accumulate_light(spec, fade, trans_accum); } } /* World Specular */ if (trans_accum.a < 0.999) { - vec3 spec = probe_evaluate_world_spec(spec_dir, roughnessSquared); + vec3 spec = probe_evaluate_world_spec(refr_dir, roughnessSquared); accumulate_light(spec, 1.0, trans_accum); } @@ -701,9 +709,13 @@ vec3 eevee_surface_glass(vec3 N, vec3 transmission_col, float roughness, float i } } - /* Specular probes */ - vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared); - vec3 refr_dir = get_specular_refraction_dominant_dir(N, V, roughness, ior); + /* Refract the view vector using the depth heuristic. + * Then later Refract a second time the already refracted + * ray using the inverse ior. */ + float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior; + vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V; + vec3 refr_pos = (refractionDepth > 0.0) ? line_plane_intersect(worldPosition, refr_V, worldPosition - N * refractionDepth, N) : worldPosition; + vec4 trans_accum = vec4(0.0); #ifdef USE_REFRACTION @@ -711,17 +723,24 @@ vec3 eevee_surface_glass(vec3 N, vec3 transmission_col, float roughness, float i if (ssrToggle && roughness < maxRoughness + 0.2) { vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; + /* Find approximated position of the 2nd refraction event. */ + vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition; + float ray_ofs = 1.0 / float(rayCount); - vec4 spec = screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand, 0.0); - if (rayCount > 1) spec += screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); - if (rayCount > 2) spec += screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); - if (rayCount > 3) spec += screen_space_refraction(viewPosition, N, V, ior, roughnessSquared, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); + vec4 spec = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand, 0.0); + if (rayCount > 1) spec += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); + if (rayCount > 2) spec += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); + if (rayCount > 3) spec += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); spec /= float(rayCount); spec.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); accumulate_light(spec.rgb, spec.a, trans_accum); } #endif + /* Specular probes */ + vec3 refr_dir = get_specular_refraction_dominant_dir(N, refr_V, roughness, final_ior); + vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared); + /* Starts at 1 because 0 is world probe */ for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999 && trans_accum.a < 0.999; ++i) { CubeData cd = probes_data[i]; @@ -733,7 +752,7 @@ vec3 eevee_surface_glass(vec3 N, vec3 transmission_col, float roughness, float i vec3 spec = probe_evaluate_cube(float(i), cd, worldPosition, spec_dir, roughness); accumulate_light(spec, fade, spec_accum); - spec = probe_evaluate_cube(float(i), cd, worldPosition, refr_dir, roughnessSquared); + spec = probe_evaluate_cube(float(i), cd, refr_pos, refr_dir, roughnessSquared); accumulate_light(spec, fade, trans_accum); } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index a4e0f85b132..f8ac92f3258 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2725,7 +2725,7 @@ void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out Closure #ifdef EEVEE_ENGINE vec3 ssr_spec; roughness = sqrt(roughness); - vec3 L = eevee_surface_glass(N, vec3(1.0), roughness, ior, int(-2), ssr_spec); + vec3 L = eevee_surface_glass(N, (refractionDepth > 0.0) ? color.rgb : vec3(1.0), roughness, ior, int(-2), ssr_spec); vec3 vN = normalize(mat3(ViewMatrix) * N); result = Closure(L * color.rgb, 1.0, vec4(ssr_spec * color.rgb, roughness), normal_encode(vN, viewCameraVec), int(-2)); #else @@ -2889,7 +2889,7 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs } result = Closure(surface_color.rgb / surface_color.a, 1.0); #else - vec3 L_trans = (transmission <= 0.0) ? vec3(0.0) : eevee_surface_glass(N, base_color.rgb, roughness, ior, int(-2), ssr_spec); + vec3 L_trans = (transmission <= 0.0) ? vec3(0.0) : eevee_surface_glass(N, base_color.rgb * ((refractionDepth > 0.0) ? base_color.rgb : vec3(1.0)), roughness, ior, int(-2), ssr_spec); vec3 L = eevee_surface_clearcoat_lit(N, diffuse, f0, roughness, CN, clearcoat, clearcoat_roughness, 1.0, int(ssr_id), ssr_spec); L = mix(L, L_trans, transmission); vec3 vN = normalize(mat3(ViewMatrix) * N); @@ -2930,11 +2930,10 @@ void node_subsurface_scattering( void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result) { #ifdef EEVEE_ENGINE - vec3 ssr_spec; + color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */ roughness = sqrt(roughness); - vec3 L = eevee_surface_refraction(N, vec3(1.0), roughness, ior, int(-2), ssr_spec); - vec3 vN = normalize(mat3(ViewMatrix) * N); - result = Closure(L * color.rgb, 1.0, vec4(ssr_spec * color.rgb, roughness), normal_encode(vN, viewCameraVec), int(-2)); + vec3 L = eevee_surface_refraction(N, vec3(1.0), roughness, ior); + result = Closure(L * color.rgb, 1.0, vec4(0.0), vec2(0.0), int(-2)); #else node_bsdf_diffuse(color, 0.0, N, result); #endif /* EEVEE_ENGINE */ diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index f4f68e112e2..220326fb01d 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -213,10 +213,11 @@ typedef struct Material { /* Transparency */ float alpha_threshold; + float refract_depth; char blend_method; char blend_shadow; char blend_flag; - char pad6; + char pad6[5]; /* image to use for image/uv space, also bake target * (not to be used shading/rendering pipeline, this is editor featyure only!). */ diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index a6427fda464..bd10bbc49ea 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1869,10 +1869,16 @@ void RNA_def_material(BlenderRNA *brna) "(avoids transparency sorting problems)"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); - prop = RNA_def_property(srna, "transparent_screen_refraction", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_screen_refraction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MA_BL_SS_REFRACTION); RNA_def_property_ui_text(prop, "Screen Space Refraction" , "Use raytraced screen space refractions"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "refraction_depth", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "refract_depth"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_text(prop, "Refraction Depth", "Approximate the thickness of the object to compute two refraction " + "event (0 is disabled)"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); /* For Preview Render */ |