diff options
Diffstat (limited to 'source/blender/draw')
8 files changed, 221 insertions, 11 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 09a090955c2..17295713001 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -530,6 +530,7 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La ubo_data->shadow_start = (float)(sh_data->layer_id); ubo_data->data_start = (float)(sh_data->cube_id); ubo_data->multi_shadow_count = (float)(sh_nbr); + ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */ ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; ubo_data->contact_bias = 0.05f * la->contact_bias; @@ -777,6 +778,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE ubo_data->shadow_start = (float)(sh_data->layer_id); ubo_data->data_start = (float)(sh_data->cascade_id); ubo_data->multi_shadow_count = (float)(sh_nbr); + ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */ ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f; ubo_data->contact_bias = 0.05f * la->contact_bias; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index dbd953553cd..4a9633b4f44 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -307,6 +307,9 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_SSS) != 0) { BLI_dynstr_appendf(ds, "#define USE_SSS\n"); } + if ((options & VAR_MAT_TRANSLUC) != 0) { + BLI_dynstr_appendf(ds, "#define USE_TRANSLUCENCY\n"); + } if ((options & VAR_MAT_VSM) != 0) { BLI_dynstr_appendf(ds, "#define SHADOW_VSM\n"); } @@ -636,7 +639,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, EEVEE_Data *vedata, - bool use_blend, bool use_multiply, bool use_refract, bool use_sss, int shadow_method) + bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method) { const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; @@ -645,6 +648,7 @@ struct GPUMaterial *EEVEE_material_mesh_get( if (use_multiply) options |= VAR_MAT_MULT; if (use_refract) options |= VAR_MAT_REFRACT; if (use_sss) options |= VAR_MAT_SSS; + if (use_translucency) options |= VAR_MAT_TRANSLUC; if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME; options |= eevee_material_shadow_option(shadow_method); @@ -977,6 +981,7 @@ static void material_opaque( const bool use_gpumat = (ma->use_nodes && ma->nodetree); const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); const bool use_sss = ((ma->blend_flag & MA_BL_SS_SUBSURFACE) != 0) && ((stl->effects->enabled_effects & EFFECT_SSS) != 0); + const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0) && ((stl->effects->enabled_effects & EFFECT_SSS) != 0); EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); @@ -987,7 +992,7 @@ static void material_opaque( /* This will have been created already, just perform a lookup. */ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get( - scene, ma, vedata, false, false, use_refract, use_sss, linfo->shadow_method) : NULL; + scene, ma, vedata, false, false, use_refract, use_sss, use_translucency, linfo->shadow_method) : NULL; *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get( scene, ma, (ma->blend_method == MA_BM_HASHED), false) : NULL; return; @@ -995,7 +1000,8 @@ static void material_opaque( if (use_gpumat) { /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, false, use_refract, use_sss, linfo->shadow_method); + *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, false, use_refract, + use_sss, use_translucency, linfo->shadow_method); *shgrp = DRW_shgroup_material_create(*gpumat, (use_refract) ? psl->refract_pass : @@ -1007,9 +1013,17 @@ static void material_opaque( add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false); if (use_sss) { + struct GPUTexture *sss_tex_profile = NULL; struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(*gpumat, - stl->effects->sss_sample_count); + stl->effects->sss_sample_count, + &sss_tex_profile); + if (sss_profile) { + if (use_translucency) { + DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile); + DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile); + } + DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); EEVEE_subsurface_add_pass(vedata, e_data.sss_count + 1, sss_profile); e_data.sss_count++; @@ -1099,7 +1113,7 @@ static void material_transparent( if (ma->use_nodes && ma->nodetree) { /* Shading */ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract, - false, linfo->shadow_method); + false, false, linfo->shadow_method); *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); if (*shgrp) { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index b1ed108bad0..6a3adb36a7c 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -116,6 +116,7 @@ enum { VAR_MAT_REFRACT = (1 << 12), VAR_MAT_VOLUME = (1 << 13), VAR_MAT_SSS = (1 << 14), + VAR_MAT_TRANSLUC = (1 << 15), }; /* Shadow Technique */ @@ -280,7 +281,7 @@ typedef struct EEVEE_Light { typedef struct EEVEE_Shadow { float near, far, bias, exp; - float shadow_start, data_start, multi_shadow_count, pad; + float shadow_start, data_start, multi_shadow_count, shadow_blur; float contact_dist, contact_bias, contact_spread, contact_thickness; } EEVEE_Shadow; @@ -639,7 +640,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, str struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo); struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, EEVEE_Data *vedata, - bool use_blend, bool use_multiply, bool use_refract, bool use_sss, int shadow_method); + bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method); struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma); struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material *ma, bool use_hashed_alpha, bool is_shadow); struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 6827d44aea4..fe6e77ddf29 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -123,7 +123,6 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_data); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_int(grp, "sampleCount", &effects->sss_sample_count, 1); DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(grp, quad, NULL); @@ -134,7 +133,6 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_int(grp, "sampleCount", &effects->sss_sample_count, 1); DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(grp, quad, NULL); 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 bd6c1923bfe..32d27838da3 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -103,6 +103,7 @@ struct ShadowCascadeData { #define sh_tex_start shadow_data_start_end.x #define sh_data_start shadow_data_start_end.y #define sh_multi_nbr shadow_data_start_end.z +#define sh_blur shadow_data_start_end.w #define sh_contact_dist contact_shadow_data.x #define sh_contact_offset contact_shadow_data.y #define sh_contact_spread contact_shadow_data.z diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 9ee713ab483..ea9711a6cad 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -5,9 +5,9 @@ layout(std140) uniform sssProfile { vec4 kernel[MAX_SSS_SAMPLES]; vec4 radii_max_radius; + int sss_samples; }; -uniform int sampleCount; uniform float jitterThreshold; uniform sampler2D depthBuffer; uniform sampler2D sssData; @@ -59,7 +59,7 @@ void main(void) /* Center sample */ vec3 accum = sss_data.rgb * kernel[0].rgb; - for (int i = 1; i < sampleCount && i < MAX_SSS_SAMPLES; i++) { + for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) { vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > jitterThreshold) ? dir : dir_rand); vec3 color = texture(sssData, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl index 5ca40cd06a2..c2e3f81aefd 100644 --- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl @@ -277,6 +277,142 @@ vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness #endif } +#define MAX_SSS_SAMPLES 65 +#define SSS_LUT_SIZE 64.0 +#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE)) +#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE)) +layout(std140) uniform sssProfile { + vec4 kernel[MAX_SSS_SAMPLES]; + vec4 radii_max_radius; + int sss_samples; +}; + +uniform sampler1D sssTexProfile; + +vec3 sss_profile(float s) { + s /= radii_max_radius.w; + return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb; +} + +vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale) +{ + vec3 vis = vec3(1.0); + + /* Only shadowed light can produce translucency */ + if (ld.l_shadowid >= 0.0) { + ShadowData data = shadows_data[int(ld.l_shadowid)]; + float delta; + + vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0); + + vec3 T, B; + make_orthonormal_basis(L.xyz / L.w, T, B); + + vec3 rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).xzw; + /* XXX This is a hack to not have noise correlation artifacts. + * A better solution to have better noise is welcome. */ + rand.yz *= fast_sqrt(fract(rand.x * 7919.0)) * data.sh_blur; + + /* We use the full l_vector.xyz so that the spread is minimize + * if the shading point is further away from the light source */ + W = W + T * rand.y + B * rand.z; + + if (ld.l_type == SUN) { + ShadowCascadeData scd = shadows_cascade_data[int(data.sh_data_start)]; + vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); + + vec4 weights = step(scd.split_end_distances, view_z); + float id = abs(4.0 - dot(weights, weights)); + + if (id > 3.0) { + return vec3(0.0); + } + + float range = abs(data.sh_far - data.sh_near); /* Same factor as in get_cascade_world_distance(). */ + + vec4 shpos = scd.shadowmat[int(id)] * vec4(W, 1.0); + float dist = shpos.z * range; + + if (shpos.z > 1.0 || shpos.z < 0.0) { + return vec3(0.0); + } + +#if defined(SHADOW_VSM) + vec2 moments = texture(shadowTexture, vec3(shpos.xy, data.sh_tex_start + id)).rg; + delta = dist - moments.x; +#else + float z = texture(shadowTexture, vec3(shpos.xy, data.sh_tex_start + id)).r; + delta = dist - z; +#endif + } + else { + vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz; + float dist = length(cubevec); + + /* If fragment is out of shadowmap range, do not occlude */ + /* XXX : we check radial distance against a cubeface distance. + * We loose quite a bit of valid area. */ + if (dist < data.sh_far) { + cubevec /= dist; + +#if defined(SHADOW_VSM) + vec2 moments = texture_octahedron(shadowTexture, vec4(cubevec, data.sh_tex_start)).rg; + delta = dist - moments.x; +#else + float z = texture_octahedron(shadowTexture, vec4(cubevec, data.sh_tex_start)).r; + delta = dist - z; +#endif + } + } + + /* XXX : Removing Area Power. */ + /* TODO : put this out of the shader. */ + float falloff; + if (ld.l_type == AREA) { + vis *= 0.0962 * (ld.l_sizex * ld.l_sizey * 4.0 * M_PI); + vis /= (l_vector.w * l_vector.w); + falloff = dot(N, l_vector.xyz / l_vector.w); + } + else if (ld.l_type == SUN) { + falloff = dot(N, -ld.l_forward); + } + else { + vis *= 0.0248 * (4.0 * ld.l_radius * ld.l_radius * M_PI * M_PI); + vis /= (l_vector.w * l_vector.w); + falloff = dot(N, l_vector.xyz / l_vector.w); + } + vis *= M_1_PI; /* Normalize */ + + /* Applying profile */ + vis *= sss_profile(abs(delta) / scale); + + /* No transmittance at grazing angle (hide artifacts) */ + vis *= saturate(falloff * 2.0); + + if (ld.l_type == SPOT) { + float z = dot(ld.l_forward, l_vector.xyz); + vec3 lL = l_vector.xyz / z; + float x = dot(ld.l_right, lL) / ld.l_sizex; + float y = dot(ld.l_up, lL) / ld.l_sizey; + + float ellipse = 1.0 / sqrt(1.0 + x * x + y * y); + + float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend); + + vis *= spotmask; + vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward)); + } + else if (ld.l_type == AREA) { + vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward)); + } + } + else { + vis = vec3(0.0); + } + + return vis; +} + #ifdef HAIR_SHADER void light_hair_common( LightData ld, vec3 N, vec3 V, vec4 l_vector, vec3 norm_view, 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 f63a9665810..44410be700b 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -810,3 +810,61 @@ vec3 eevee_surface_glass(vec3 N, vec3 transmission_col, float roughness, float i return out_light; } + +/* ----------- Translucency ----------- */ + +vec3 eevee_surface_translucent_lit(vec3 N, vec3 albedo, float sss_scale) +{ +#ifndef USE_TRANSLUCENCY + return vec3(0.0); +#endif + + vec3 V = cameraVec; + + /* Zero length vectors cause issues, see: T51979. */ +#if 0 + N = normalize(N); +#else + { + float len = length(N); + if (isnan(len)) { + return vec3(0.0); + } + N /= len; + } +#endif + + /* We only enlit the backfaces */ + N = -N; + + /* ---------------- SCENE LAMPS LIGHTING ----------------- */ + +#ifdef HAIR_SHADER + vec3 norm_view = cross(V, N); + norm_view = normalize(cross(norm_view, N)); /* Normal facing view */ +#endif + + vec3 diff = vec3(0.0); + for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + LightData ld = lights_data[i]; + + vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ + l_vector.xyz = ld.l_position - worldPosition; + l_vector.w = length(l_vector.xyz); + +#ifdef HAIR_SHADER + vec3 norm_lamp, view_vec; + float occlu_trans, occlu; + light_hair_common(ld, N, V, l_vector, norm_view, occlu_trans, occlu, norm_lamp, view_vec); + + diff += ld.l_color * light_translucent(ld, worldPosition, norm_lamp, l_vector, sss_scale) * occlu_trans; +#else + diff += ld.l_color * light_translucent(ld, worldPosition, N, l_vector, sss_scale); +#endif + } + + /* Accumulate outgoing radiance */ + vec3 out_light = diff * albedo; + + return out_light; +} |