diff options
5 files changed, 56 insertions, 193 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 10da80ece54..1cf5650205d 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -428,7 +428,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) linfo->shadow_cube_size, max_ii(1, linfo->num_cube_layer * 6), shadow_pool_format, - DRW_TEX_FILTER, + DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL); } @@ -437,7 +437,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) linfo->shadow_cascade_size, max_ii(1, linfo->num_cascade_layer), shadow_pool_format, - DRW_TEX_FILTER, + DRW_TEX_FILTER | DRW_TEX_COMPARE, NULL); } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index af9e2bc67f4..41df16ab22d 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1753,6 +1753,15 @@ void EEVEE_materials_free(void) void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) { + /* We sample the shadowmaps using shadow sampler. We need to enable Comparison mode. + * TODO(fclem) avoid this by using sampler objects.*/ + GPU_texture_bind(sldata->shadow_cube_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cube_pool, true); + GPU_texture_unbind(sldata->shadow_cube_pool); + GPU_texture_bind(sldata->shadow_cascade_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cascade_pool, true); + GPU_texture_unbind(sldata->shadow_cascade_pool); + for (int i = 0; i < VAR_MAT_MAX; ++i) { if (psl->default_pass[i]) { DRW_draw_pass(psl->default_pass[i]); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index b31925e8eff..4d29e597dae 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -333,7 +333,7 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat } } -void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; @@ -356,6 +356,15 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v } if (!DRW_pass_is_empty(psl->sss_translucency_ps)) { + /* We sample the shadowmaps using normal sampler. We need to disable Comparison mode. + * TODO(fclem) avoid this by using sampler objects.*/ + GPU_texture_bind(sldata->shadow_cube_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cube_pool, false); + GPU_texture_unbind(sldata->shadow_cube_pool); + GPU_texture_bind(sldata->shadow_cascade_pool, 0); + GPU_texture_compare_mode(sldata->shadow_cascade_pool, false); + GPU_texture_unbind(sldata->shadow_cascade_pool); + GPU_framebuffer_bind(fbl->sss_translucency_fb); DRW_draw_pass(psl->sss_translucency_ps); } diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 5558e2ef074..23bf8b59648 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -1,6 +1,6 @@ -uniform sampler2DArray shadowCubeTexture; -uniform sampler2DArray shadowCascadeTexture; +uniform sampler2DArrayShadow shadowCubeTexture; +uniform sampler2DArrayShadow shadowCascadeTexture; #define LAMPS_LIB @@ -51,19 +51,6 @@ vec2 cubeFaceCoordEEVEE(vec3 P, float face) } } -float cubeFaceDepthEEVEE(vec3 P, float face) -{ - if (face < 2.0) { - return abs(P.x); - } - else if (face < 4.0) { - return abs(P.y); - } - else { - return abs(P.z); - } -} - vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube) { /* Manual Shadow Cube Layer indexing. */ @@ -78,168 +65,25 @@ vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id) return texture(tex, vec3(co, cascade_id)); } -/** Convert screenspace derivatives to texture space derivatives. - * As described by John R. Isidoro in GDC 2006 presentation "Shadow Mapping: GPU-based Tips and - *Techniques". https://developer.amd.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf - **/ -vec2 texture_space_derivatives(vec3 duvfdx, vec3 duvfdy) -{ - /* Invert texture Jacobian and use chain rule to compute ddist/du and ddist/dv - * |ddist/du| = |du/dx du/dy|-T * |ddist/dx| - * |ddist/dv| |dv/dx dv/dy| |ddist/dy| */ - - /* // Multiply ddist/dx and ddist/dy by inverse transpose of Jacobian - * float invDet = 1 / ((duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x)); - * // Top row of 2x2 - * ddist_duv.x = duvdist_dy.y * duvdist_dx.w; // invJtrans[0][0] * ddist_dx - * ddist_duv.x -= duvdist_dx.y * duvdist_dy.w; // invJtrans[0][1] * ddist_dy - * // Bottom row of 2x2 - * ddist_duv.y = duvdist_dx.x * duvdist_dy.w; // invJtrans[1][1] * ddist_dy - * ddist_duv.y -= duvdist_dy.x * duvdist_dx.w; // invJtrans[1][0] * ddist_dx - * ddist_duv *= invDet; - **/ - - /* Optimized version. */ - vec2 a = duvfdx.xy * duvfdy.yx; - vec4 b = duvfdy.yzzx * duvfdx.zyxz; - return (b.xz - b.yw) / (a.x - a.y); -} - -/** Returns Receiver Plane Depth Bias - * As described by John R. Isidoro in GDC 2006 presentation "Shadow Mapping: GPU-based Tips and - * Techniques". https://developer.amd.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf - */ -float shadowmap_bias(vec2 co, vec2 tap_co, vec2 dwduv) -{ - return dot(tap_co - co, dwduv); -} - -/** - * Parameters: - * shadow_tx : shadowmap to sample. - * co : the original sample position. - * ref : the original depth to test (Depth of the surface in shadowmap space). - * co_ofs : the actual offseted sample position. - * dwduv : result of texture_space_derivatives(). - **/ -float filtered_and_biased_shadow_test(sampler2DArray shadow_tx, - vec2 co, - float layer, - float ref, - float max_bias, - vec2 co_ofs, - vec2 dwduv) -{ - vec4 biases, depths; - vec2 texture_size = vec2(textureSize(shadow_tx, 0).xy); - vec3 texel_size = vec3(1.0 / texture_size, 0.0); - /* Center texel coordinate to match hardware filtering */ - vec2 texel_uv = co_ofs * texture_size.xy - 0.5; - vec2 texel_fract = fract(texel_uv); - vec2 texel_floor = (floor(texel_uv) + 0.5) * texel_size.xy; - /* Calc bias for each sample */ - biases.x = shadowmap_bias(co, texel_floor + texel_size.zy, dwduv); - biases.y = shadowmap_bias(co, texel_floor + texel_size.xy, dwduv); - biases.z = shadowmap_bias(co, texel_floor + texel_size.xz, dwduv); - biases.w = shadowmap_bias(co, texel_floor + texel_size.zz, dwduv); - /* Gather samples */ -#ifdef GPU_ARB_texture_gather - /* Note: To make sure that we get the exact same result we use texel center. - * This is because Anisotropic filtering is offsetting the coordinate. */ - depths = textureGather(shadow_tx, vec3(texel_floor + texel_size.xy * 0.5, layer)); -#else - depths.x = texture(shadow_tx, vec3(texel_floor + texel_size.zy, layer)).x; - depths.y = texture(shadow_tx, vec3(texel_floor + texel_size.xy, layer)).x; - depths.z = texture(shadow_tx, vec3(texel_floor + texel_size.xz, layer)).x; - depths.w = texture(shadow_tx, vec3(texel_floor + texel_size.zz, layer)).x; -#endif - /* Take absolute of bias to avoid overshadowing in proximity area. - * Also limit the bias in case the geom is almost perpendicular to the shadow source - * to avoid light leaking. */ - vec4 refs = saturate(ref - min(vec4(max_bias), abs(biases))); - /* Bilinear PCF. */ - vec4 tests = step(refs, depths); - tests.xy = mix(tests.wz, tests.xy, texel_fract.y); - return saturate(mix(tests.x, tests.y, texel_fract.x)); -} - -float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W) +float sample_cube_shadow(ShadowData sd, ShadowCubeData scd, float texid, vec3 W) { vec3 cubevec = W - scd.position.xyz; -#ifndef VOLUMETRICS - vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy; - float ofs_len = fast_sqrt(rand.z) * sd.sh_blur * 0.1; - vec3 cubevec_nor = normalize(cubevec); - vec3 T, B; - make_orthonormal_basis(cubevec_nor, T, B); - vec3 cubevec_ofs = cubevec_nor + (T * rand.x + B * rand.y) * ofs_len; - /* Use face of the offseted cubevec. */ - float face_id = cubeFaceIndexEEVEE(cubevec_ofs); - vec2 uv_ofs = cubeFaceCoordEEVEE(cubevec_ofs, face_id); - - /* To avoid derivatives discontinuity, we compute derivatives - * on a smooth linear function (unormalized cubevec), - * and manually do the derivative of the uv coords. */ - vec3 duvwdx, duvwdy; - vec3 dPdx = cubevec + dFdx(cubevec); - vec3 dPdy = cubevec + dFdy(cubevec); - vec2 uv = cubeFaceCoordEEVEE(cubevec, face_id); - duvwdx.xy = cubeFaceCoordEEVEE(dPdx, face_id) - uv; - duvwdy.xy = cubeFaceCoordEEVEE(dPdy, face_id) - uv; - - float dist = cubeFaceDepthEEVEE(cubevec, face_id); - duvwdx.z = cubeFaceDepthEEVEE(dPdx, face_id); - duvwdy.z = cubeFaceDepthEEVEE(dPdy, face_id); - - dist = buffer_depth(true, dist, sd.sh_far, sd.sh_near); - duvwdx.z = buffer_depth(true, duvwdx.z, sd.sh_far, sd.sh_near) - dist; - duvwdy.z = buffer_depth(true, duvwdy.z, sd.sh_far, sd.sh_near) - dist; - - vec2 dwduv = texture_space_derivatives(duvwdx, duvwdy); - - float layer = texid * 6.0 + face_id; - return filtered_and_biased_shadow_test( - shadowCubeTexture, uv, layer, dist, sd.sh_bias * 0.15, uv_ofs, dwduv); -#else float dist = max_v3(abs(cubevec)); dist = buffer_depth(true, dist, sd.sh_far, sd.sh_near); - float face_id = cubeFaceIndexEEVEE(cubevec); - vec2 uv = cubeFaceCoordEEVEE(cubevec, face_id); - float layer = texid * 6.0 + face_id; - return filtered_and_biased_shadow_test(shadowCubeTexture, uv, layer, dist, 0.0, uv, vec2(0.0)); -#endif + /* Manual Shadow Cube Layer indexing. */ + /* TODO Shadow Cube Array. */ + float face = cubeFaceIndexEEVEE(cubevec); + vec2 coord = cubeFaceCoordEEVEE(cubevec, face); + + return texture(shadowCubeTexture, vec4(coord, texid * 6.0 + face, dist)); } -float evaluate_cascade(ShadowData sd, mat4 shadowmat, mat4 shadowmat0, vec3 W, float texid) +float sample_cascade_shadow(ShadowData sd, mat4 shadowmat, mat4 shadowmat0, vec3 W, float texid) { - vec4 shpos = shadowmat * vec4(W, 1.0); - -#ifndef VOLUMETRICS - float fac = length(shadowmat0[0].xyz) / length(shadowmat[0].xyz); - vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy; - float ofs_len = fast_sqrt(rand.z) * sd.sh_blur * 0.05 / fac; - /* This assumes that shadowmap is a square (w == h) - * and that all cascades are the same dimensions. */ - vec2 uv_ofs = shpos.xy + rand.xy * ofs_len; - - vec2 dwduv = texture_space_derivatives(dFdx(shpos.xyz), dFdy(shpos.xyz)); - - float vis = filtered_and_biased_shadow_test( - shadowCascadeTexture, shpos.xy, texid, shpos.z, sd.sh_bias * 0.75, uv_ofs, dwduv); -#else - float vis = filtered_and_biased_shadow_test( - shadowCascadeTexture, shpos.xy, texid, shpos.z, 0.0, shpos.xy, vec2(0.0)); -#endif - - /* If fragment is out of shadowmap range, do not occlude */ - if (shpos.z < 1.0 && shpos.z > 0.0) { - return vis; - } - else { - return 1.0; - } + vec4 coord = shadowmat * vec4(W, 1.0); + return texture(shadowCascadeTexture, vec4(coord.xy, texid, coord.z)); } float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W) @@ -255,26 +99,26 @@ float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W) /* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */ /* TODO OPTI: Only do 2 samples and blend. */ - vis.x = evaluate_cascade(sd, - shadows_cascade_data[scd_id].shadowmat[0], - shadows_cascade_data[scd_id].shadowmat[0], - W, - texid + 0); - vis.y = evaluate_cascade(sd, - shadows_cascade_data[scd_id].shadowmat[1], - shadows_cascade_data[scd_id].shadowmat[0], - W, - texid + 1); - vis.z = evaluate_cascade(sd, - shadows_cascade_data[scd_id].shadowmat[2], - shadows_cascade_data[scd_id].shadowmat[0], - W, - texid + 2); - vis.w = evaluate_cascade(sd, - shadows_cascade_data[scd_id].shadowmat[3], - shadows_cascade_data[scd_id].shadowmat[0], - W, - texid + 3); + vis.x = sample_cascade_shadow(sd, + shadows_cascade_data[scd_id].shadowmat[0], + shadows_cascade_data[scd_id].shadowmat[0], + W, + texid + 0); + vis.y = sample_cascade_shadow(sd, + shadows_cascade_data[scd_id].shadowmat[1], + shadows_cascade_data[scd_id].shadowmat[0], + W, + texid + 1); + vis.z = sample_cascade_shadow(sd, + shadows_cascade_data[scd_id].shadowmat[2], + shadows_cascade_data[scd_id].shadowmat[0], + W, + texid + 2); + vis.w = sample_cascade_shadow(sd, + shadows_cascade_data[scd_id].shadowmat[3], + shadows_cascade_data[scd_id].shadowmat[0], + W, + texid + 3); float weight_sum = dot(vec4(1.0), weights); if (weight_sum > 0.9999) { @@ -346,7 +190,7 @@ float light_visibility(LightData ld, vis *= shadow_cascade(data, int(data.sh_data_start), data.sh_tex_start, W); } else { - vis *= shadow_cubemap( + vis *= sample_cube_shadow( data, shadows_cube_data[int(data.sh_data_start)], data.sh_tex_start, W); } diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 54c874241ac..1274b41c407 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -285,7 +285,8 @@ void drw_state_set(DRWState state) if ((test = CHANGED_TO(DRW_STATE_SHADOW_OFFSET))) { if (test == 1) { glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.0f, 1.0f); + /* 2.0 Seems to be the lowest possible slope bias that works in every case. */ + glPolygonOffset(2.0f, 1.0f); } else { glDisable(GL_POLYGON_OFFSET_FILL); |