Eevee: Shadow map refactor

Reviewed By: brecht

Differential Revision: http://developer.blender.org/D5659
This commit is contained in:
Clément Foucault 2019-08-22 16:04:25 +02:00
parent ca58936f2f
commit d8aaf25c23
Notes: blender-bot 2023-02-14 09:09:43 +01:00
Referenced by issue #70249, Marbling effect on Eevee and subsurface scattering...
Referenced by issue #68471, Shadow System Refactor
47 changed files with 1988 additions and 2865 deletions

View File

@ -175,17 +175,10 @@ class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
col = layout.column()
sub = col.column(align=True)
sub.prop(light, "shadow_buffer_clip_start", text="Clip Start")
if light.type == 'SUN':
sub.prop(light, "shadow_buffer_clip_end", text="End")
col.prop(light, "shadow_buffer_soft", text="Softness")
col.separator()
if light.type != 'SUN':
sub.prop(light, "shadow_buffer_clip_start", text="Clip Start")
col.prop(light, "shadow_buffer_bias", text="Bias")
col.prop(light, "shadow_buffer_exp", text="Exponent")
col.prop(light, "shadow_buffer_bleed_bias", text="Bleed Bias")
class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel):
@ -245,7 +238,6 @@ class DATA_PT_EEVEE_shadow_contact(DataButtonsPanel, Panel):
col.active = light.use_shadow and light.use_contact_shadow
col.prop(light, "contact_shadow_distance", text="Distance")
col.prop(light, "contact_shadow_soft_size", text="Softness")
col.prop(light, "contact_shadow_bias", text="Bias")
col.prop(light, "contact_shadow_thickness", text="Thickness")
@ -335,8 +327,8 @@ classes = (
DATA_PT_EEVEE_light,
DATA_PT_EEVEE_light_distance,
DATA_PT_EEVEE_shadow,
DATA_PT_EEVEE_shadow_contact,
DATA_PT_EEVEE_shadow_cascaded_shadow_map,
DATA_PT_EEVEE_shadow_contact,
DATA_PT_area,
DATA_PT_spot,
DATA_PT_falloff_curve,

View File

@ -314,7 +314,6 @@ class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel):
col = layout.column()
col.prop(props, "sss_samples")
col.prop(props, "sss_jitter_threshold")
col.prop(props, "use_sss_separate_albedo")
class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):
@ -366,7 +365,6 @@ class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel):
props = scene.eevee
col = layout.column()
col.prop(props, "shadow_method")
col.prop(props, "shadow_cube_size", text="Cube Size")
col.prop(props, "shadow_cascade_size", text="Cascade Size")
col.prop(props, "use_shadow_high_bitdepth")

View File

@ -961,7 +961,6 @@ void BKE_scene_init(Scene *sce)
sce->eevee.motion_blur_samples = 8;
sce->eevee.motion_blur_shutter = 0.5f;
sce->eevee.shadow_method = SHADOW_ESM;
sce->eevee.shadow_cube_size = 512;
sce->eevee.shadow_cascade_size = 1024;
@ -972,7 +971,7 @@ void BKE_scene_init(Scene *sce)
sce->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS |
SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION |
SCE_EEVEE_SSR_HALF_RESOLUTION;
SCE_EEVEE_SSR_HALF_RESOLUTION | SCE_EEVEE_SHADOW_SOFT;
}
Scene *BKE_scene_add(Main *bmain, const char *name)

View File

@ -1854,7 +1854,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION);
// EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED);
EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
// EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED);
EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION);
EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION);

View File

@ -265,6 +265,9 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
/* Change default cubemap quality. */
scene->eevee.gi_filter_quality = 3.0f;
/* Enable Soft Shadows by default. */
scene->eevee.flag |= SCE_EEVEE_SHADOW_SOFT;
/* Be sure curfalloff and primitive are initializated */
ToolSettings *ts = scene->toolsettings;
if (ts->gp_sculpt.cur_falloff == NULL) {

View File

@ -103,7 +103,11 @@ set(SRC
engines/eevee/eevee_occlusion.c
engines/eevee/eevee_render.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_sampling.c
engines/eevee/eevee_shaders.c
engines/eevee/eevee_shadows.c
engines/eevee/eevee_shadows_cube.c
engines/eevee/eevee_shadows_cascade.c
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
@ -201,6 +205,7 @@ data_to_c_simple(engines/eevee/shaders/effect_mist_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/effect_subsurface_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_translucency_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
@ -209,10 +214,6 @@ data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_process_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_process_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_store_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/shadow_copy_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)

View File

@ -35,23 +35,13 @@ void EEVEE_view_layer_data_free(void *storage)
MEM_SAFE_FREE(sldata->lights);
DRW_UBO_FREE_SAFE(sldata->light_ubo);
DRW_UBO_FREE_SAFE(sldata->shadow_ubo);
DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_store_fb);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_copy_fb);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_target_fb);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_store_fb);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_copy_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_fb);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters);
MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags);
MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
for (int i = 0; i < 2; i++) {
MEM_SAFE_FREE(sldata->shcasters_buffers[i].bbox);
MEM_SAFE_FREE(sldata->shcasters_buffers[i].update);
}
if (sldata->fallback_lightcache) {
EEVEE_lightcache_free(sldata->fallback_lightcache);
@ -153,7 +143,6 @@ static void eevee_light_data_init(DrawData *dd)
{
EEVEE_LightEngineData *led = (EEVEE_LightEngineData *)dd;
led->need_update = true;
led->prev_cube_shadow_id = -1;
}
EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob)

View File

@ -84,7 +84,7 @@ static void eevee_engine_init(void *ved)
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, camera, false);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_lights_init(sldata);
EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
}
@ -139,7 +139,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob)
}
if (cast_shadow) {
EEVEE_lights_cache_shcaster_object_add(sldata, ob);
EEVEE_shadows_caster_register(sldata, ob);
}
}
@ -223,7 +223,7 @@ static void eevee_draw_background(void *vedata)
/* Refresh shadows */
DRW_stats_group_start("Shadows");
EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view);
EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
DRW_stats_group_end();
if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) &&
@ -269,9 +269,7 @@ static void eevee_draw_background(void *vedata)
if (DRW_state_draw_background()) {
DRW_draw_pass(psl->background_pass);
}
EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->material_pass_cull);
EEVEE_materials_draw_opaque(sldata, psl);
EEVEE_subsurface_data_render(sldata, vedata);
DRW_stats_group_end();
@ -368,11 +366,21 @@ static void eevee_draw_background(void *vedata)
}
break;
case 8:
if (effects->sss_data) {
DRW_transform_to_display(effects->sss_data, false, false);
if (effects->sss_irradiance) {
DRW_transform_to_display(effects->sss_irradiance, false, false);
}
break;
case 9:
if (effects->sss_radius) {
DRW_transform_to_display(effects->sss_radius, false, false);
}
break;
case 10:
if (effects->sss_albedo) {
DRW_transform_to_display(effects->sss_albedo, false, false);
}
break;
case 11:
if (effects->velocity_tx) {
DRW_transform_to_display(effects->velocity_tx, false, false);
}
@ -467,7 +475,7 @@ static void eevee_engine_free(void)
EEVEE_depth_of_field_free();
EEVEE_effects_free();
EEVEE_lightprobes_free();
EEVEE_lights_free();
EEVEE_shadows_free();
EEVEE_materials_free();
EEVEE_mist_free();
EEVEE_motion_blur_free();

View File

@ -743,7 +743,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb
EEVEE_effects_init(sldata, vedata, NULL, true);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_lights_init(sldata);
EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
EEVEE_effects_cache_init(sldata, vedata);

View File

@ -904,7 +904,7 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
struct GPUFrameBuffer **face_fb = user_data->face_fb;
/* Be sure that cascaded shadow maps are updated. */
EEVEE_draw_shadows(sldata, user_data->vedata, views[face]);
EEVEE_shadows_draw(sldata, user_data->vedata, views[face]);
GPU_framebuffer_bind(face_fb[face]);
GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
@ -912,11 +912,9 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
DRW_draw_pass(psl->depth_pass);
DRW_draw_pass(psl->depth_pass_cull);
DRW_draw_pass(psl->probe_background);
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->material_pass_cull);
EEVEE_materials_draw_opaque(sldata, psl);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_draw_pass(psl->sss_pass_cull);
EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->transparent_pass);
}
@ -964,7 +962,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
DRW_stats_group_start("Planar Reflection");
/* Be sure that cascaded shadow maps are updated. */
EEVEE_draw_shadows(sldata, vedata, stl->g_data->planar_views[layer]);
EEVEE_shadows_draw(sldata, vedata, stl->g_data->planar_views[layer]);
GPU_framebuffer_bind(fbl->planarref_fb);
GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
@ -987,9 +985,7 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
GPU_framebuffer_bind(fbl->planarref_fb);
/* Shading pass */
EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->material_pass_cull);
EEVEE_materials_draw_opaque(sldata, psl);
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_draw_pass(psl->sss_pass_cull);
DRW_draw_pass(psl->refract_pass);

File diff suppressed because it is too large Load Diff

View File

@ -63,8 +63,6 @@ static struct {
struct GPUTexture *util_tex;
struct GPUTexture *noise_tex;
struct GPUUniformBuffer *dummy_sss_profile;
uint sss_count;
float alpha_hash_offset;
@ -273,21 +271,6 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void)
return e_data.util_tex;
}
static int eevee_material_shadow_option(int shadow_method)
{
switch (shadow_method) {
case SHADOW_ESM:
return VAR_MAT_ESM;
case SHADOW_VSM:
return VAR_MAT_VSM;
default:
BLI_assert(!"Incorrect Shadow Method");
break;
}
return 0;
}
static char *eevee_get_defines(int options)
{
char *str = NULL;
@ -322,23 +305,8 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_REFRACT) != 0) {
BLI_dynstr_append(ds, "#define USE_REFRACTION\n");
}
if ((options & VAR_MAT_SSSALBED) != 0) {
BLI_dynstr_append(ds, "#define USE_SSS_ALBEDO\n");
}
if ((options & VAR_MAT_TRANSLUC) != 0) {
BLI_dynstr_append(ds, "#define USE_TRANSLUCENCY\n");
}
if ((options & VAR_MAT_VSM) != 0) {
BLI_dynstr_append(ds, "#define SHADOW_VSM\n");
}
if ((options & VAR_MAT_ESM) != 0) {
BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
}
if ((options & VAR_MAT_LOOKDEV) != 0) {
/* Auto config shadow method. Avoid more permutation. */
BLI_assert((options & (VAR_MAT_VSM | VAR_MAT_ESM)) == 0);
BLI_dynstr_append(ds, "#define LOOKDEV\n");
BLI_dynstr_append(ds, "#define SHADOW_ESM\n");
}
str = BLI_dynstr_get_cstring(ds);
@ -435,11 +403,6 @@ static void create_default_shader(int options)
MEM_freeN(frag_str);
}
static void eevee_init_dummys(void)
{
e_data.dummy_sss_profile = GPU_material_create_sss_profile_ubo();
}
static void eevee_init_noise_texture(void)
{
e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise);
@ -631,7 +594,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
eevee_init_util_texture();
eevee_init_noise_texture();
eevee_init_dummys();
}
if (!DRW_state_is_image_render() && ((stl->effects->enabled_effects & EFFECT_TAA) == 0)) {
@ -731,22 +693,15 @@ 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,
EEVEE_Data *UNUSED(vedata),
bool use_blend,
bool use_refract,
bool use_translucency,
int shadow_method)
bool use_refract)
{
EEVEE_EffectsInfo *effects = vedata->stl->effects;
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH;
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT);
SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED);
SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC);
options |= eevee_material_shadow_option(shadow_method);
GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
@ -835,13 +790,11 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
return mat;
}
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method)
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
{
const void *engine = &DRW_engine_viewport_eevee_type;
int options = VAR_MAT_MESH | VAR_MAT_HAIR;
options |= eevee_material_shadow_option(shadow_method);
GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
if (mat) {
return mat;
@ -872,8 +825,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye
DRWPass *pass,
bool is_hair,
bool use_blend,
bool use_ssr,
int shadow_method)
bool use_ssr)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
@ -882,8 +834,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
options |= eevee_material_shadow_option(shadow_method);
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
@ -903,8 +853,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
ParticleSystem *psys,
ModifierData *md,
bool is_hair,
bool use_ssr,
int shadow_method)
bool use_ssr)
{
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
@ -916,8 +865,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
options |= eevee_material_shadow_option(shadow_method);
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
}
@ -1164,7 +1111,6 @@ static void material_opaque(Material *ma,
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_LightsInfo *linfo = sldata->lights;
bool use_diffuse, use_glossy, use_refract;
float *color_p = &ma->r;
@ -1186,11 +1132,8 @@ static void material_opaque(Material *ma,
*shgrp_depth_clip = emsg->depth_clip_grp;
/* This will have been created already, just perform a lookup. */
*gpumat =
(use_gpumat) ?
EEVEE_material_mesh_get(
scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method) :
NULL;
*gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) :
NULL;
*gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
NULL;
@ -1203,8 +1146,7 @@ static void material_opaque(Material *ma,
static float half = 0.5f;
/* Shading */
*gpumat = EEVEE_material_mesh_get(
scene, ma, vedata, false, use_ssrefract, use_translucency, linfo->shadow_method);
*gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract);
eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
@ -1311,15 +1253,15 @@ static void material_opaque(Material *ma,
*gpumat, 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);
}
/* Limit of 8 bit stencil buffer. ID 255 is refraction. */
if (e_data.sss_count < 254) {
DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
int sss_id = e_data.sss_count + 1;
DRW_shgroup_stencil_mask(*shgrp, sss_id);
EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile);
if (use_translucency) {
EEVEE_subsurface_translucency_add_pass(
sldata, vedata, sss_id, sss_profile, sss_tex_profile);
}
e_data.sss_count++;
}
else {
@ -1327,19 +1269,6 @@ static void material_opaque(Material *ma,
printf("Error: Too many different Subsurface shader in the scene.\n");
}
}
else {
if (use_translucency) {
/* NOTE: This is a nasty workaround, because the sss profile might not have been
* generated but the UBO is still declared in this case even if not used.
* But rendering without a bound UBO might result in crashes on certain platform. */
DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
}
}
}
else {
if (use_translucency) {
DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
}
}
break;
}
@ -1360,8 +1289,7 @@ static void material_opaque(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
*shgrp = EEVEE_default_shading_group_get(
sldata, vedata, NULL, NULL, NULL, false, use_ssr, linfo->shadow_method);
*shgrp = EEVEE_default_shading_group_get(sldata, vedata, NULL, NULL, NULL, false, use_ssr);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
@ -1401,7 +1329,6 @@ static void material_transparent(Material *ma,
Scene *scene = draw_ctx->scene;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_LightsInfo *linfo = sldata->lights;
const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
const bool use_ssrefract = (((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
@ -1417,8 +1344,7 @@ static void material_transparent(Material *ma,
static float half = 0.5f;
/* Shading */
*gpumat = EEVEE_material_mesh_get(
scene, ma, vedata, true, use_ssrefract, false, linfo->shadow_method);
*gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract);
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS: {
@ -1461,7 +1387,7 @@ static void material_transparent(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
*shgrp = EEVEE_default_shading_group_create(
sldata, vedata, psl->transparent_pass, false, true, false, linfo->shadow_method);
sldata, vedata, psl->transparent_pass, false, true, false);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
@ -1650,18 +1576,18 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
struct GPUMaterial *gpumat;
switch (ma_array[i]->blend_shadow) {
case MA_BS_SOLID:
EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob);
*cast_shadow = true;
break;
case MA_BS_CLIP:
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true);
EEVEE_lights_cache_shcaster_material_add(
EEVEE_shadows_caster_material_add(
sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold);
*cast_shadow = true;
break;
case MA_BS_HASHED:
gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true);
EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
*cast_shadow = true;
break;
case MA_BS_NONE:
@ -1728,8 +1654,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
static float half = 0.5f;
static float error_col[3] = {1.0f, 0.0f, 1.0f};
static float compile_col[3] = {0.5f, 0.5f, 0.5f};
struct GPUMaterial *gpumat = EEVEE_material_hair_get(
scene, ma, sldata->lights->shadow_method);
struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma);
switch (GPU_material_status(gpumat)) {
case GPU_MAT_SUCCESS: {
@ -1774,8 +1699,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
/* Fallback to default shader */
if (shgrp == NULL) {
shgrp = EEVEE_default_shading_group_get(
sldata, vedata, ob, psys, md, true, use_ssr, sldata->lights->shadow_method);
shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, use_ssr);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
@ -1819,14 +1743,16 @@ void EEVEE_materials_free(void)
DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
DRW_TEXTURE_FREE_SAFE(e_data.noise_tex);
DRW_UBO_FREE_SAFE(e_data.dummy_sss_profile);
}
void EEVEE_draw_default_passes(EEVEE_PassList *psl)
void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl)
{
for (int i = 0; i < VAR_MAT_MAX; ++i) {
if (psl->default_pass[i]) {
DRW_draw_pass(psl->default_pass[i]);
}
}
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->material_pass_cull);
}

View File

@ -23,9 +23,12 @@
#ifndef __EEVEE_PRIVATE_H__
#define __EEVEE_PRIVATE_H__
#include "DRW_render.h"
#include "BLI_bitmap.h"
#include "DNA_lightprobe_types.h"
struct EEVEE_BoundSphere;
struct EEVEE_ShadowCasterBuffer;
struct GPUFrameBuffer;
struct Object;
@ -39,11 +42,13 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */
#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
#define MAX_CASCADE_NUM 4
#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW 128 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
// #define DEBUG_SHADOW_DISTRIBUTION
/* Only define one of these. */
// #define IRRADIANCE_SH_L2
// #define IRRADIANCE_CUBEMAP
@ -150,14 +155,12 @@ enum {
VAR_MAT_PROBE = (1 << 1),
VAR_MAT_HAIR = (1 << 2),
VAR_MAT_BLEND = (1 << 3),
VAR_MAT_VSM = (1 << 4),
VAR_MAT_ESM = (1 << 5),
VAR_MAT_VOLUME = (1 << 6),
VAR_MAT_LOOKDEV = (1 << 7),
VAR_MAT_VOLUME = (1 << 4),
VAR_MAT_LOOKDEV = (1 << 5),
/* Max number of variation */
/* IMPORTANT : Leave it last and set
* it's value accordingly. */
VAR_MAT_MAX = (1 << 8),
VAR_MAT_MAX = (1 << 6),
/* These are options that are not counted in VAR_MAT_MAX
* because they are not cumulative with the others above. */
VAR_MAT_CLIP = (1 << 9),
@ -165,8 +168,6 @@ enum {
VAR_MAT_MULT = (1 << 11),
VAR_MAT_SHADOW = (1 << 12),
VAR_MAT_REFRACT = (1 << 13),
VAR_MAT_TRANSLUC = (1 << 15),
VAR_MAT_SSSALBED = (1 << 16),
};
/* ************ PROBE UBO ************* */
@ -190,10 +191,6 @@ typedef struct EEVEE_PlanarReflection {
/* --------------------------------------- */
typedef struct EEVEE_BoundSphere {
float center[3], radius;
} EEVEE_BoundSphere;
typedef struct EEVEE_BoundBox {
float center[3], halfdim[3];
} EEVEE_BoundBox;
@ -201,12 +198,6 @@ typedef struct EEVEE_BoundBox {
typedef struct EEVEE_PassList {
/* Shadows */
struct DRWPass *shadow_pass;
struct DRWPass *shadow_cube_copy_pass;
struct DRWPass *shadow_cube_store_pass;
struct DRWPass *shadow_cube_store_high_pass;
struct DRWPass *shadow_cascade_copy_pass;
struct DRWPass *shadow_cascade_store_pass;
struct DRWPass *shadow_cascade_store_high_pass;
/* Probes */
struct DRWPass *probe_background;
@ -242,6 +233,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *sss_blur_ps;
struct DRWPass *sss_resolve_ps;
struct DRWPass *sss_accum_ps;
struct DRWPass *sss_translucency_ps;
struct DRWPass *color_downsample_ps;
struct DRWPass *color_downsample_cube_ps;
struct DRWPass *velocity_resolve;
@ -292,6 +284,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *sss_blit_fb;
struct GPUFrameBuffer *sss_resolve_fb;
struct GPUFrameBuffer *sss_clear_fb;
struct GPUFrameBuffer *sss_translucency_fb;
struct GPUFrameBuffer *sss_accum_fb;
struct GPUFrameBuffer *dof_down_fb;
struct GPUFrameBuffer *dof_scatter_fb;
@ -368,7 +361,7 @@ typedef struct EEVEE_StorageList {
typedef struct EEVEE_Light {
float position[3], invsqrdist;
float color[3], spec;
float spotsize, spotblend, radius, shadowid;
float spotsize, spotblend, radius, shadow_id;
float rightvec[3], sizex;
float upvec[3], sizey;
float forwardvec[3], light_type;
@ -378,13 +371,13 @@ typedef struct EEVEE_Light {
#define LAMPTYPE_AREA_ELLIPSE 100.0f
typedef struct EEVEE_Shadow {
float near, far, bias, exp;
float shadow_start, data_start, multi_shadow_count, shadow_blur;
float near, far, bias, type_data_id;
float contact_dist, contact_bias, contact_spread, contact_thickness;
} EEVEE_Shadow;
typedef struct EEVEE_ShadowCube {
float position[3], pad;
float shadowmat[4][4];
float position[3], _pad0[1];
} EEVEE_ShadowCube;
typedef struct EEVEE_ShadowCascade {
@ -392,42 +385,34 @@ typedef struct EEVEE_ShadowCascade {
float shadowmat[MAX_CASCADE_NUM][4][4];
float split_start[4];
float split_end[4];
float shadow_vec[3], tex_id;
} EEVEE_ShadowCascade;
typedef struct EEVEE_ShadowRender {
int shadow_samples_len[MAX_CASCADE_NUM];
float shadow_samples_len_inv[MAX_CASCADE_NUM];
float filter_size[MAX_CASCADE_NUM];
int view_count;
int base_id;
float cube_texel_size;
float stored_texel_size;
float clip_near;
float clip_far;
float exponent;
float pad;
} EEVEE_ShadowRender;
typedef struct EEVEE_ShadowCascadeRender {
/* World->Light->NDC : used for rendering the shadow map. */
float projmat[MAX_CASCADE_NUM][4][4];
float viewmat[4][4], viewinv[4][4];
float radius[MAX_CASCADE_NUM];
float cascade_max_dist;
float cascade_exponent;
float cascade_fade;
int cascade_count;
} EEVEE_ShadowCascadeRender;
BLI_STATIC_ASSERT_ALIGN(EEVEE_Light, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_Shadow, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCube, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowCascade, 16)
BLI_STATIC_ASSERT_ALIGN(EEVEE_ShadowRender, 16)
/* This is just a really long bitflag with special function to access it. */
#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8)
typedef struct EEVEE_LightBits {
uchar fields[MAX_LIGHTBITS_FIELDS];
} EEVEE_LightBits;
typedef struct EEVEE_ShadowCaster {
struct EEVEE_LightBits bits;
struct EEVEE_BoundBox bbox;
} EEVEE_ShadowCaster;
BLI_STATIC_ASSERT(sizeof(EEVEE_Shadow) * MAX_SHADOW +
sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE +
sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE <
16384,
"Shadow UBO is too big!!!")
typedef struct EEVEE_ShadowCasterBuffer {
struct EEVEE_ShadowCaster *shadow_casters;
char *flags;
struct EEVEE_BoundBox *bbox;
BLI_bitmap *update;
uint alloc_count;
uint count;
} EEVEE_ShadowCasterBuffer;
@ -437,42 +422,31 @@ typedef struct EEVEE_LightsInfo {
int num_light, cache_num_light;
int num_cube_layer, cache_num_cube_layer;
int num_cascade_layer, cache_num_cascade_layer;
int gpu_cube_len, gpu_cascade_len, gpu_shadow_len;
int cpu_cube_len, cpu_cascade_len;
int update_flag;
int shadow_cube_size, shadow_cascade_size, shadow_method;
int cube_len, cascade_len, shadow_len;
int shadow_cube_size, shadow_cascade_size;
bool shadow_high_bitdepth, soft_shadows;
int shadow_cube_store_size;
/* List of lights in the scene. */
/* XXX This is fragile, can get out of sync quickly. */
struct Object *light_ref[MAX_LIGHT];
struct Object *shadow_cube_ref[MAX_SHADOW_CUBE];
struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE];
/* UBO Storage : data used by UBO */
struct EEVEE_Light light_data[MAX_LIGHT];
struct EEVEE_ShadowRender shadow_render_data;
struct EEVEE_Shadow shadow_data[MAX_SHADOW];
struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
/* Additionnal rendering info for cascade. */
struct EEVEE_ShadowCascadeRender shadow_cascade_render[MAX_SHADOW_CASCADE];
/* Back index in light_data. */
uchar shadow_cube_light_indices[MAX_SHADOW_CUBE];
uchar shadow_cascade_light_indices[MAX_SHADOW_CASCADE];
/* Update bitmap. */
BLI_bitmap sh_cube_update[BLI_BITMAP_SIZE(MAX_SHADOW_CUBE)];
/* Lights tracking */
int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */
struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
/* Pointers only. */
struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer;
struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer;
struct BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
/* List of bbox and update bitmap. Double buffered. */
struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer, *shcaster_backbuffer;
/* AABB of all shadow casters combined. */
struct {
float min[3], max[3];
} shcaster_aabb;
} EEVEE_LightsInfo;
/* EEVEE_LightsInfo->shadow_casters_flag */
enum {
SHADOW_CASTER_PRUNED = (1 << 0),
SHADOW_CASTER_UPDATED = (1 << 1),
};
/* EEVEE_LightsInfo->update_flag */
enum {
LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
};
/* ************ PROBE DATA ************* */
typedef struct EEVEE_LightProbeVisTest {
struct Collection *collection; /* Skip test if NULL */
@ -552,8 +526,8 @@ typedef struct EEVEE_EffectsInfo {
bool swap_double_buffer;
/* SSSS */
int sss_sample_count;
bool sss_separate_albedo;
struct GPUTexture *sss_data; /* Textures from pool */
struct GPUTexture *sss_irradiance; /* Textures from pool */
struct GPUTexture *sss_radius;
struct GPUTexture *sss_albedo;
struct GPUTexture *sss_blur;
struct GPUTexture *sss_stencil;
@ -711,20 +685,10 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuffer *light_ubo;
struct GPUUniformBuffer *shadow_ubo;
struct GPUUniformBuffer *shadow_render_ubo;
struct GPUUniformBuffer *shadow_samples_ubo;
struct GPUFrameBuffer *shadow_cube_target_fb;
struct GPUFrameBuffer *shadow_cube_store_fb;
struct GPUFrameBuffer *shadow_cube_copy_fb;
struct GPUFrameBuffer *shadow_cascade_target_fb;
struct GPUFrameBuffer *shadow_cascade_store_fb;
struct GPUFrameBuffer *shadow_cascade_copy_fb;
struct GPUFrameBuffer *shadow_fb;
struct GPUTexture *shadow_cube_target;
struct GPUTexture *shadow_cube_blur;
struct GPUTexture *shadow_cascade_target;
struct GPUTexture *shadow_cascade_blur;
struct GPUTexture *shadow_cube_pool;
struct GPUTexture *shadow_cascade_pool;
@ -746,23 +710,6 @@ typedef struct EEVEE_ViewLayerData {
/* ************ OBJECT DATA ************ */
typedef struct EEVEE_LightData {
short light_id, shadow_id;
} EEVEE_LightData;
typedef struct EEVEE_ShadowCubeData {
short light_id, shadow_id, cube_id, layer_id;
} EEVEE_ShadowCubeData;
typedef struct EEVEE_ShadowCascadeData {
short light_id, shadow_id, cascade_id, layer_id;
/* World->Light->NDC : used for rendering the shadow map. */
float viewprojmat[MAX_CASCADE_NUM][4][4]; /* Could be removed. */
float projmat[MAX_CASCADE_NUM][4][4];
float viewmat[4][4], viewinv[4][4];
float radius[MAX_CASCADE_NUM];
} EEVEE_ShadowCascadeData;
/* These are the structs stored inside Objects.
* It works even if the object is in multiple layers
* because we don't get the same "Object *" for each layer. */
@ -770,13 +717,6 @@ typedef struct EEVEE_LightEngineData {
DrawData dd;
bool need_update;
/* This needs to be out of the union to avoid undefined behavior. */
short prev_cube_shadow_id;
union {
struct EEVEE_LightData ld;
struct EEVEE_ShadowCubeData scd;
struct EEVEE_ShadowCascadeData scad;
} data;
} EEVEE_LightEngineData;
typedef struct EEVEE_LightProbeEngineData {
@ -895,43 +835,67 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
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_refract,
bool use_translucency,
int shadow_method);
struct GPUMaterial *EEVEE_material_mesh_get(
struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract);
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);
struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma);
void EEVEE_materials_free(void);
void EEVEE_draw_default_passes(EEVEE_PassList *psl);
void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]);
/* eevee_lights.c */
void EEVEE_lights_init(EEVEE_ViewLayerData *sldata);
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]);
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *sldata,
EEVEE_StorageList *stl,
struct GPUBatch *geom,
Object *ob);
void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata,
EEVEE_PassList *psl,
struct GPUMaterial *gpumat,
struct GPUBatch *geom,
struct Object *ob,
const float *alpha_threshold);
void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
void EEVEE_lights_free(void);
/* eevee_shadows.c */
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh);
void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata);
void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata,
EEVEE_StorageList *stl,
struct GPUBatch *geom,
Object *ob);
void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
EEVEE_PassList *psl,
struct GPUMaterial *gpumat,
struct GPUBatch *geom,
struct Object *ob,
const float *alpha_threshold);
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs);
void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view);
void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index);
void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
DRWView *view,
int cascade_index);
void EEVEE_shadows_free(void);
/* eevee_sampling.c */
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3]);
void EEVEE_sample_rectangle(int sample_ofs,
const float x_axis[3],
const float y_axis[3],
float size_x,
float size_y,
float rsample[3]);
void EEVEE_sample_ellipse(int sample_ofs,
const float x_axis[3],
const float y_axis[3],
float size_x,
float size_y,
float rsample[3]);
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
void EEVEE_shaders_lightprobe_shaders_init(void);
@ -1044,6 +1008,11 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile);
void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile,
struct GPUTexture *sss_tex_profile);
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);

View File

@ -133,7 +133,7 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
/* EEVEE_effects_init needs to go first for TAA */
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_lights_init(sldata);
EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
/* INIT CACHE */
@ -198,7 +198,7 @@ void EEVEE_render_cache(void *vedata,
}
if (cast_shadow) {
EEVEE_lights_cache_shcaster_object_add(sldata, ob);
EEVEE_shadows_caster_register(sldata, ob);
}
}
@ -478,7 +478,8 @@ static void eevee_render_draw_background(EEVEE_Data *vedata)
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_normal_input),
GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_specrough_input),
GPU_ATTACHMENT_TEXTURE(stl->effects->sss_data),
GPU_ATTACHMENT_TEXTURE(stl->effects->sss_irradiance),
GPU_ATTACHMENT_TEXTURE(stl->effects->sss_radius),
GPU_ATTACHMENT_TEXTURE(stl->effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
}
@ -582,8 +583,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
EEVEE_lightprobes_refresh_planar(sldata, vedata);
/* Refresh Shadows */
EEVEE_lights_update(sldata, vedata);
EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view);
EEVEE_shadows_update(sldata, vedata);
EEVEE_shadows_draw(sldata, vedata, stl->effects->taa_view);
/* Set matrices. */
DRW_view_set_active(stl->effects->taa_view);
@ -605,9 +606,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Shading pass */
eevee_render_draw_background(vedata);
GPU_framebuffer_bind(fbl->main_fb);
EEVEE_draw_default_passes(psl);
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->material_pass_cull);
EEVEE_materials_draw_opaque(sldata, psl);
EEVEE_subsurface_data_render(sldata, vedata);
/* Effects pre-transparency */
EEVEE_subsurface_compute(sldata, vedata);

View File

@ -0,0 +1,111 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2019, Blender Foundation.
*/
/** \file
* \ingroup EEVEE
*/
#include "eevee_private.h"
#include "BLI_rand.h"
/**
* Special ball distribution:
* Point are distributed in a way that when they are orthogonally
* projected into any plane, the resulting distribution is (close to)
* a uniform disc distribution.
*/
void EEVEE_sample_ball(int sample_ofs, float radius, float rsample[3])
{
double ht_point[3];
double ht_offset[3] = {0.0, 0.0, 0.0};
uint ht_primes[3] = {2, 3, 7};
BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
float omega = ht_point[1] * 2.0f * M_PI;
rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */
float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */
rsample[0] = r * cosf(omega);
rsample[1] = r * sinf(omega);
radius *= sqrt(sqrt(ht_point[2]));
mul_v3_fl(rsample, radius);
}
void EEVEE_sample_rectangle(int sample_ofs,
const float x_axis[3],
const float y_axis[3],
float size_x,
float size_y,
float rsample[3])
{
double ht_point[2];
double ht_offset[2] = {0.0, 0.0};
uint ht_primes[2] = {2, 3};
BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
/* Change ditribution center to be 0,0 */
ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0];
ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1];
zero_v3(rsample);
madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x);
madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y);
}
void EEVEE_sample_ellipse(int sample_ofs,
const float x_axis[3],
const float y_axis[3],
float size_x,
float size_y,
float rsample[3])
{
double ht_point[2];
double ht_offset[2] = {0.0, 0.0};
uint ht_primes[2] = {2, 3};
BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
/* Uniform disc sampling. */
float omega = ht_point[1] * 2.0f * M_PI;
float r = sqrtf(ht_point[0]);
ht_point[0] = r * cosf(omega) * size_x;
ht_point[1] = r * sinf(omega) * size_y;
zero_v3(rsample);
madd_v3_v3fl(rsample, x_axis, ht_point[0]);
madd_v3_v3fl(rsample, y_axis, ht_point[1]);
}
void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4])
{
double ht_point[3];
double ht_offset[3] = {0.0, 0.0, 0.0};
uint ht_primes[3] = {2, 3, 5};
BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
rotate_m4(r_mat, 'X', ht_point[0] * scale);
rotate_m4(r_mat, 'Y', ht_point[1] * scale);
rotate_m4(r_mat, 'Z', ht_point[2] * scale);
}

View File

@ -0,0 +1,412 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2019, Blender Foundation.
*/
/** \file
* \ingroup EEVEE
*/
#include "BLI_sys_types.h" /* bool */
// #include "BLI_dynstr.h"
// #include "BLI_rand.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
#include "eevee_private.h"
#define SH_CASTER_ALLOC_CHUNK 32
static struct {
struct GPUShader *shadow_sh;
} e_data = {NULL}; /* Engine data */
extern char datatoc_shadow_vert_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_common_view_lib_glsl[];
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh)
{
evsh->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
evsh->contact_bias = 0.05f * la->contact_bias;
evsh->contact_thickness = la->contact_thickness;
}
void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata)
{
const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
if (!e_data.shadow_sh) {
e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl,
NULL,
datatoc_shadow_frag_glsl,
datatoc_common_view_lib_glsl,
NULL);
}
if (!sldata->lights) {
sldata->lights = MEM_callocN(sizeof(EEVEE_LightsInfo), "EEVEE_LightsInfo");
sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
for (int i = 0; i < 2; ++i) {
sldata->shcasters_buffers[i].bbox = MEM_callocN(
sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__);
sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__);
sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK;
sldata->shcasters_buffers[i].count = 0;
}
sldata->lights->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
sldata->lights->shcaster_backbuffer = &sldata->shcasters_buffers[1];
}
/* Flip buffers */
SWAP(EEVEE_ShadowCasterBuffer *,
sldata->lights->shcaster_frontbuffer,
sldata->lights->shcaster_backbuffer);
int sh_cube_size = scene_eval->eevee.shadow_cube_size;
int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
sldata->lights->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
EEVEE_LightsInfo *linfo = sldata->lights;
if ((linfo->shadow_cube_size != sh_cube_size) ||
(linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
CLAMP(sh_cube_size, 1, 4096);
}
if ((linfo->shadow_cascade_size != sh_cascade_size) ||
(linfo->shadow_high_bitdepth != sh_high_bitdepth)) {
BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
CLAMP(sh_cascade_size, 1, 4096);
}
linfo->shadow_high_bitdepth = sh_high_bitdepth;
linfo->shadow_cube_size = sh_cube_size;
linfo->shadow_cascade_size = sh_cascade_size;
}
void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_LightsInfo *linfo = sldata->lights;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
frontbuffer->count = 0;
linfo->num_cube_layer = 0;
linfo->num_cascade_layer = 0;
linfo->cube_len = linfo->cascade_len = linfo->shadow_len = 0;
/* Shadow Casters: Reset flags. */
BLI_bitmap_set_all(backbuffer->update, true, backbuffer->alloc_count);
/* Is this one needed? */
BLI_bitmap_set_all(frontbuffer->update, false, frontbuffer->alloc_count);
INIT_MINMAX(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
{
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_SHADOW_OFFSET;
DRW_PASS_CREATE(psl->shadow_pass, state);
stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
}
}
/* Add a shadow caster to the shadowpasses */
void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_StorageList *stl,
struct GPUBatch *geom,
Object *ob)
{
DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
}
void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
EEVEE_PassList *psl,
struct GPUMaterial *gpumat,
struct GPUBatch *geom,
struct Object *ob,
const float *alpha_threshold)
{
/* TODO / PERF : reuse the same shading group for objects with the same material */
DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
if (grp == NULL) {
return;
}
/* Grrr needed for correctness but not 99% of the time not needed.
* TODO detect when needed? */
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
if (alpha_threshold != NULL) {
DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
}
DRW_shgroup_call(grp, geom, ob);
}
/* Make that object update shadow casting lights inside its influence bounding box. */
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
{
EEVEE_LightsInfo *linfo = sldata->lights;
EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
bool update = true;
int id = frontbuffer->count;
/* Make sure shadow_casters is big enough. */
if (id + 1 >= frontbuffer->alloc_count) {
frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK;
frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
}
if (ob->base_flag & BASE_FROM_DUPLI) {
/* Duplis will always refresh the shadowmaps as if they were deleted each frame. */
/* TODO(fclem) fix this. */
update = true;
}
else {
EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
int past_id = oedata->shadow_caster_id;
oedata->shadow_caster_id = id;
/* Update flags in backbuffer. */
if (past_id > -1 && past_id < backbuffer->count) {
BLI_BITMAP_SET(backbuffer->update, past_id, oedata->need_update);
}
update = oedata->need_update;
oedata->need_update = false;
}
if (update) {
BLI_BITMAP_ENABLE(frontbuffer->update, id);
}
/* Update World AABB in frontbuffer. */
BoundBox *bb = BKE_object_boundbox_get(ob);
float min[3], max[3];
INIT_MINMAX(min, max);
for (int i = 0; i < 8; ++i) {
float vec[3];
copy_v3_v3(vec, bb->vec[i]);
mul_m4_v3(ob->obmat, vec);
minmax_v3v3_v3(min, max, vec);
}
EEVEE_BoundBox *aabb = &frontbuffer->bbox[id];
add_v3_v3v3(aabb->center, min, max);
mul_v3_fl(aabb->center, 0.5f);
sub_v3_v3v3(aabb->halfdim, aabb->center, max);
aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, min);
minmax_v3v3_v3(linfo->shcaster_aabb.min, linfo->shcaster_aabb.max, max);
frontbuffer->count++;
}
/* Used for checking if object is inside the shadow volume. */
static bool sphere_bbox_intersect(const BoundSphere *bs, const EEVEE_BoundBox *bb)
{
/* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
/* TODO test speed with AABB vs Sphere. */
bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
return x && y && z;
}
void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_LightsInfo *linfo = sldata->lights;
EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
eGPUTextureFormat shadow_pool_format = (linfo->shadow_high_bitdepth) ? GPU_DEPTH_COMPONENT24 :
GPU_DEPTH_COMPONENT16;
/* Setup enough layers. */
/* Free textures if number mismatch. */
if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
linfo->cache_num_cube_layer = linfo->num_cube_layer;
/* Update all lights. */
BLI_bitmap_set_all(&linfo->sh_cube_update[0], true, MAX_LIGHT);
}
if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
}
if (!sldata->shadow_cube_pool) {
/* TODO shadowcube array. */
int cube_size = linfo->shadow_cube_size + ((true) ? 2 : 0);
sldata->shadow_cube_pool = DRW_texture_create_2d_array(cube_size,
cube_size,
max_ii(1, linfo->num_cube_layer * 6),
shadow_pool_format,
DRW_TEX_FILTER | DRW_TEX_COMPARE,
NULL);
}
if (!sldata->shadow_cascade_pool) {
sldata->shadow_cascade_pool = DRW_texture_create_2d_array(linfo->shadow_cascade_size,
linfo->shadow_cascade_size,
max_ii(1, linfo->num_cascade_layer),
shadow_pool_format,
DRW_TEX_FILTER | DRW_TEX_COMPARE,
NULL);
}
if (sldata->shadow_fb == NULL) {
sldata->shadow_fb = GPU_framebuffer_create();
}
/* Gather all light own update bits. to avoid costly intersection check. */
for (int j = 0; j < linfo->cube_len; j++) {
const EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[j];
/* Setup shadow cube in UBO and tag for update if necessary. */
if (EEVEE_shadows_cube_setup(linfo, evli, effects->taa_current_sample - 1)) {
BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
}
}
/* TODO(fclem) This part can be slow, optimize it. */
EEVEE_BoundBox *bbox = backbuffer->bbox;
BoundSphere *bsphere = linfo->shadow_bounds;
/* Search for deleted shadow casters or if shcaster WAS in shadow radius. */
for (int i = 0; i < backbuffer->count; ++i) {
/* If the shadowcaster has been deleted or updated. */
if (BLI_BITMAP_TEST(backbuffer->update, i)) {
for (int j = 0; j < linfo->cube_len; j++) {
if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
}
}
}
}
}
/* Search for updates in current shadow casters. */
bbox = frontbuffer->bbox;
for (int i = 0; i < frontbuffer->count; i++) {
/* If the shadowcaster has been updated. */
if (BLI_BITMAP_TEST(frontbuffer->update, i)) {
for (int j = 0; j < linfo->cube_len; j++) {
if (!BLI_BITMAP_TEST(&linfo->sh_cube_update[0], j)) {
if (sphere_bbox_intersect(&bsphere[j], &bbox[i])) {
BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], j);
}
}
}
}
}
/* Resize shcasters buffers if too big. */
if (frontbuffer->alloc_count - frontbuffer->count > SH_CASTER_ALLOC_CHUNK) {
frontbuffer->alloc_count = (frontbuffer->count / SH_CASTER_ALLOC_CHUNK) *
SH_CASTER_ALLOC_CHUNK;
frontbuffer->alloc_count += (frontbuffer->count % SH_CASTER_ALLOC_CHUNK != 0) ?
SH_CASTER_ALLOC_CHUNK :
0;
frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox,
sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count);
BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count);
}
}
/* this refresh lights shadow buffers */
void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view)
{
EEVEE_LightsInfo *linfo = sldata->lights;
int saved_ray_type = sldata->common_data.ray_type;
/* Precompute all shadow/view test before rendering and trashing the culling cache. */
BLI_bitmap *cube_visible = BLI_BITMAP_NEW_ALLOCA(MAX_SHADOW_CUBE);
bool any_visible = false;
for (int cube = 0; cube < linfo->cube_len; cube++) {
if (DRW_culling_sphere_test(view, linfo->shadow_bounds + cube)) {
BLI_BITMAP_ENABLE(cube_visible, cube);
any_visible = true;
}
}
if (!any_visible && linfo->cascade_len == 0) {
sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
}
DRW_stats_group_start("Cube Shadow Maps");
{
for (int cube = 0; cube < linfo->cube_len; cube++) {
if (BLI_BITMAP_TEST(cube_visible, cube) && BLI_BITMAP_TEST(linfo->sh_cube_update, cube)) {
EEVEE_shadows_draw_cubemap(sldata, vedata, cube);
}
}
}
DRW_stats_group_end();
DRW_stats_group_start("Cascaded Shadow Maps");
{
for (int cascade = 0; cascade < linfo->cascade_len; cascade++) {
EEVEE_shadows_draw_cascades(sldata, vedata, view, cascade);
}
}
DRW_stats_group_end();
DRW_view_set_active(view);
DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
if (!any_visible && linfo->cascade_len == 0) {
sldata->common_data.ray_type = saved_ray_type;
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
}
}
void EEVEE_shadows_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
}

View File

@ -0,0 +1,439 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2019, Blender Foundation.
*/
/** \file
* \ingroup EEVEE
*/
#include "BLI_rect.h"
#include "BLI_sys_types.h" /* bool */
#include "BKE_object.h"
#include "eevee_private.h"
#include "BLI_rand.h" /* needs to be after for some reason. */
void EEVEE_shadows_cascade_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
{
if (linfo->cascade_len >= MAX_SHADOW_CASCADE) {
return;
}
const Light *la = (Light *)ob->data;
EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + linfo->cascade_len;
EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render + linfo->cascade_len;
sh_data->bias = max_ff(la->bias * 0.00002f, 0.0f);
eevee_contact_shadow_setup(la, sh_data);
linfo->shadow_cascade_light_indices[linfo->cascade_len] = linfo->num_light;
evli->shadow_id = linfo->shadow_len++;
sh_data->type_data_id = linfo->cascade_len++;
csm_data->tex_id = linfo->num_cascade_layer;
csm_render->cascade_fade = la->cascade_fade;
csm_render->cascade_count = la->cascade_count;
csm_render->cascade_exponent = la->cascade_exponent;
csm_render->cascade_max_dist = la->cascade_max_dist;
linfo->num_cascade_layer += la->cascade_count;
}
static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
{
float jitter[3];
#ifndef DEBUG_SHADOW_DISTRIBUTION
EEVEE_sample_ellipse(sample_ofs, mat[0], mat[1], radius, radius, jitter);
#else
for (int i = 0; i <= sample_ofs; ++i) {
EEVEE_sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
float p[3];
add_v3_v3v3(p, jitter, mat[2]);
DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
}
#endif
add_v3_v3(mat[2], jitter);
orthogonalize_m4(mat, 2);
}
static double round_to_digits(double value, int digits)
{
double factor = pow(10.0, digits - ceil(log10(fabs(value))));
return round(value * factor) / factor;
}
static void frustum_min_bounding_sphere(const float corners[8][3],
float r_center[3],
float *r_radius)
{
#if 0 /* Simple solution but waste too much space. */
float minvec[3], maxvec[3];
/* compute the bounding box */
INIT_MINMAX(minvec, maxvec);
for (int i = 0; i < 8; ++i) {
minmax_v3v3_v3(minvec, maxvec, corners[i]);
}
/* compute the bounding sphere of this box */
r_radius = len_v3v3(minvec, maxvec) * 0.5f;
add_v3_v3v3(r_center, minvec, maxvec);
mul_v3_fl(r_center, 0.5f);
#else
/* Find averaged center. */
zero_v3(r_center);
for (int i = 0; i < 8; ++i) {
add_v3_v3(r_center, corners[i]);
}
mul_v3_fl(r_center, 1.0f / 8.0f);
/* Search the largest distance from the sphere center. */
*r_radius = 0.0f;
for (int i = 0; i < 8; ++i) {
float rad = len_squared_v3v3(corners[i], r_center);
if (rad > *r_radius) {
*r_radius = rad;
}
}
/* TODO try to reduce the radius further by moving the center.
* Remember we need a __stable__ solution! */
/* Try to reduce float imprecision leading to shimmering. */
*r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
#endif
}
BLI_INLINE float lerp(float t, float a, float b)
{
return ((a) + (t) * ((b) - (a)));
}
static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
EEVEE_Light *evli,
DRWView *view,
float view_near,
float view_far,
int sample_ofs)
{
EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
(int)shdw_data->type_data_id;
int cascade_nbr = csm_render->cascade_count;
float cascade_fade = csm_render->cascade_fade;
float cascade_max_dist = csm_render->cascade_max_dist;
float cascade_exponent = csm_render->cascade_exponent;
float jitter_ofs[2];
double ht_point[2];
double ht_offset[2] = {0.0, 0.0};
uint ht_primes[2] = {2, 3};
BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
/* Not really sure why we need 4.0 factor here. */
jitter_ofs[0] = (ht_point[0] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
jitter_ofs[1] = (ht_point[1] * 2.0 - 1.0) * 4.0 / linfo->shadow_cascade_size;
/* Camera Matrices */
float persinv[4][4], vp_projmat[4][4];
DRW_view_persmat_get(view, persinv, true);
DRW_view_winmat_get(view, vp_projmat, false);
bool is_persp = DRW_view_is_persp_get(view);
/* obmat = Object Space > World Space */
/* viewmat = World Space > View Space */
float(*viewmat)[4] = csm_render->viewmat;
eevee_light_matrix_get(evli, viewmat);
/* At this point, viewmat == normalize_m4(obmat) */
if (linfo->soft_shadows) {
shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
}
copy_m4_m4(csm_render->viewinv, viewmat);
invert_m4(viewmat);
copy_v3_v3(csm_data->shadow_vec, csm_render->viewinv[2]);
/* Compute near and far value based on all shadow casters cumulated AABBs. */
float sh_near = -1.0e30f, sh_far = 1.0e30f;
BoundBox shcaster_bounds;
BKE_boundbox_init_from_minmax(
&shcaster_bounds, linfo->shcaster_aabb.min, linfo->shcaster_aabb.max);
#ifdef DEBUG_CSM
float dbg_col1[4] = {1.0f, 0.5f, 0.6f, 1.0f};
DRW_debug_bbox(&shcaster_bounds, dbg_col1);
#endif
for (int i = 0; i < 8; i++) {
mul_m4_v3(viewmat, shcaster_bounds.vec[i]);
sh_near = max_ff(sh_near, shcaster_bounds.vec[i][2]);
sh_far = min_ff(sh_far, shcaster_bounds.vec[i][2]);
}
#ifdef DEBUG_CSM
float dbg_col2[4] = {0.5f, 1.0f, 0.6f, 1.0f};
float pts[2][3] = {{0.0, 0.0, sh_near}, {0.0, 0.0, sh_far}};
mul_m4_v3(csm_render->viewinv, pts[0]);
mul_m4_v3(csm_render->viewinv, pts[1]);
DRW_debug_sphere(pts[0], 1.0f, dbg_col1);
DRW_debug_sphere(pts[1], 1.0f, dbg_col2);
#endif
/* The rest of the function is assuming inverted Z. */
/* Add a little bias to avoid invalid matrices. */
sh_far = -(sh_far - 1e-3);
sh_near = -sh_near;
/* The technique consists into splitting
* the view frustum into several sub-frustum
* that are individually receiving one shadow map */
float csm_start, csm_end;
if (is_persp) {
csm_start = view_near;
csm_end = max_ff(view_far, -cascade_max_dist);
/* Avoid artifacts */
csm_end = min_ff(view_near, csm_end);
}
else {
csm_start = -view_far;
csm_end = view_far;
}
/* init near/far */
for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
csm_data->split_start[c] = csm_end;
csm_data->split_end[c] = csm_end;
}
/* Compute split planes */
float splits_start_ndc[MAX_CASCADE_NUM];
float splits_end_ndc[MAX_CASCADE_NUM];
{
/* Nearest plane */
float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
/* TODO: we don't need full m4 multiply here */
mul_m4_v4(vp_projmat, p);
splits_start_ndc[0] = p[2];
if (is_persp) {
splits_start_ndc[0] /= p[3];
}
}
{
/* Farthest plane */
float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
/* TODO: we don't need full m4 multiply here */
mul_m4_v4(vp_projmat, p);
splits_end_ndc[cascade_nbr - 1] = p[2];
if (is_persp) {
splits_end_ndc[cascade_nbr - 1] /= p[3];
}
}
csm_data->split_start[0] = csm_start;
csm_data->split_end[cascade_nbr - 1] = csm_end;
for (int c = 1; c < cascade_nbr; ++c) {
/* View Space */
float linear_split = lerp(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
if (is_persp) {
csm_data->split_start[c] = lerp(cascade_exponent, linear_split, exp_split);
}
else {
csm_data->split_start[c] = linear_split;
}
csm_data->split_end[c - 1] = csm_data->split_start[c];
/* Add some overlap for smooth transition */
csm_data->split_start[c] = lerp(cascade_fade,
csm_data->split_end[c - 1],
(c > 1) ? csm_data->split_end[c - 2] :
csm_data->split_start[0]);
/* NDC Space */
{
float p[4] = {1.0f, 1.0f, csm_data->split_start[c], 1.0f};
/* TODO: we don't need full m4 multiply here */
mul_m4_v4(vp_projmat, p);
splits_start_ndc[c] = p[2];
if (is_persp) {
splits_start_ndc[c] /= p[3];
}
}
{
float p[4] = {1.0f, 1.0f, csm_data->split_end[c - 1], 1.0f};
/* TODO: we don't need full m4 multiply here */
mul_m4_v4(vp_projmat, p);
splits_end_ndc[c - 1] = p[2];
if (is_persp) {
splits_end_ndc[c - 1] /= p[3];
}
}
}
/* Set last cascade split fade distance into the first split_start. */
float prev_split = (cascade_nbr > 1) ? csm_data->split_end[cascade_nbr - 2] :
csm_data->split_start[0];
csm_data->split_start[0] = lerp(cascade_fade, csm_data->split_end[cascade_nbr - 1], prev_split);
/* For each cascade */
for (int c = 0; c < cascade_nbr; ++c) {
float(*projmat)[4] = csm_render->projmat[c];
/* Given 8 frustum corners */
float corners[8][3] = {
/* Near Cap */
{1.0f, -1.0f, splits_start_ndc[c]},
{-1.0f, -1.0f, splits_start_ndc[c]},
{-1.0f, 1.0f, splits_start_ndc[c]},
{1.0f, 1.0f, splits_start_ndc[c]},
/* Far Cap */
{1.0f, -1.0f, splits_end_ndc[c]},
{-1.0f, -1.0f, splits_end_ndc[c]},
{-1.0f, 1.0f, splits_end_ndc[c]},
{1.0f, 1.0f, splits_end_ndc[c]},
};
/* Transform them into world space */
for (int i = 0; i < 8; ++i) {
mul_project_m4_v3(persinv, corners[i]);
}
float center[3];
frustum_min_bounding_sphere(corners, center, &(csm_render->radius[c]));
#ifdef DEBUG_CSM
float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
if (c < 3) {
dbg_col[c] = 1.0f;
}
DRW_debug_bbox((BoundBox *)&corners, dbg_col);
DRW_debug_sphere(center, csm_render->radius[c], dbg_col);
#endif
/* Project into lightspace */
mul_m4_v3(viewmat, center);
/* Snap projection center to nearest texel to cancel shimmering. */
float shadow_origin[2], shadow_texco[2];
/* Light to texture space. */
mul_v2_v2fl(
shadow_origin, center, linfo->shadow_cascade_size / (2.0f * csm_render->radius[c]));
/* Find the nearest texel. */
shadow_texco[0] = roundf(shadow_origin[0]);
shadow_texco[1] = roundf(shadow_origin[1]);
/* Compute offset. */
sub_v2_v2(shadow_texco, shadow_origin);
/* Texture to light space. */
mul_v2_fl(shadow_texco, (2.0f * csm_render->radius[c]) / linfo->shadow_cascade_size);
/* Apply offset. */
add_v2_v2(center, shadow_texco);
/* Expand the projection to cover frustum range */
rctf rect_cascade;
BLI_rctf_init_pt_radius(&rect_cascade, center, csm_render->radius[c]);
orthographic_m4(projmat,
rect_cascade.xmin,
rect_cascade.xmax,
rect_cascade.ymin,
rect_cascade.ymax,
sh_near,
sh_far);
/* Anti-Aliasing */
if (linfo->soft_shadows) {
add_v2_v2(projmat[3], jitter_ofs);
}
float viewprojmat[4][4];
mul_m4_m4m4(viewprojmat, projmat, viewmat);
mul_m4_m4m4(csm_data->shadowmat[c], texcomat, viewprojmat);
#ifdef DEBUG_CSM
DRW_debug_m4_as_bbox(viewprojmat, dbg_col, true);
#endif
}
shdw_data->near = sh_near;
shdw_data->far = sh_far;
}
static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeRender *csm_render,
DRWView *view[MAX_CASCADE_NUM])
{
for (int i = 0; i < csm_render->cascade_count; i++) {
if (view[i] == NULL) {
view[i] = DRW_view_create(csm_render->viewmat, csm_render->projmat[i], NULL, NULL, NULL);
}
else {
DRW_view_update(view[i], csm_render->viewmat, csm_render->projmat[i], NULL, NULL);
}
}
}
void EEVEE_shadows_draw_cascades(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
DRWView *view,
int cascade_index)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_PrivateData *g_data = stl->g_data;
EEVEE_LightsInfo *linfo = sldata->lights;
EEVEE_Light *evli = linfo->light_data + linfo->shadow_cascade_light_indices[cascade_index];
EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
(int)shdw_data->type_data_id;
float near = DRW_view_near_distance_get(view);
float far = DRW_view_far_distance_get(view);
eevee_shadow_cascade_setup(linfo, evli, view, near, far, effects->taa_current_sample - 1);
/* Meh, Reusing the cube views. */
BLI_assert(MAX_CASCADE_NUM <= 6);
eevee_ensure_cascade_views(csm_render, g_data->cube_views);
/* Render shadow cascades */
/* Render cascade separately: seems to be faster for the general case.
* The only time it's more beneficial is when the CPU culling overhead
* outweigh the instancing overhead. which is rarely the case. */
for (int j = 0; j < csm_render->cascade_count; j++) {
DRW_view_set_active(g_data->cube_views[j]);
int layer = csm_data->tex_id + j;
GPU_framebuffer_texture_layer_attach(
sldata->shadow_fb, sldata->shadow_cascade_pool, 0, layer, 0);
GPU_framebuffer_bind(sldata->shadow_fb);
GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
DRW_draw_pass(psl->shadow_pass);
}
}

View File

@ -0,0 +1,223 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2019, Blender Foundation.
*/
/** \file
* \ingroup EEVEE
*/
#include "eevee_private.h"
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, Object *ob)
{
if (linfo->cube_len >= MAX_SHADOW_CUBE) {
return;
}
const Light *la = (Light *)ob->data;
EEVEE_Shadow *sh_data = linfo->shadow_data + linfo->shadow_len;
/* Always update dupli lights as EEVEE_LightEngineData is not saved.
* Same issue with dupli shadow casters. */
bool update = (ob->base_flag & BASE_FROM_DUPLI) != 0;
if (!update) {
EEVEE_LightEngineData *led = EEVEE_light_data_ensure(ob);
if (led->need_update) {
update = true;
led->need_update = false;
}
}
if (update) {
BLI_BITMAP_ENABLE(&linfo->sh_cube_update[0], linfo->cube_len);
}
sh_data->near = max_ff(la->clipsta, 1e-8f);
sh_data->bias = max_ff(la->bias * 0.05f, 0.0f);
eevee_contact_shadow_setup(la, sh_data);
/* Saving light bounds for later. */
BoundSphere *cube_bound = linfo->shadow_bounds + linfo->cube_len;
copy_v3_v3(cube_bound->center, evli->position);
cube_bound->radius = sqrt(1.0f / evli->invsqrdist);
linfo->shadow_cube_light_indices[linfo->cube_len] = linfo->num_light;
evli->shadow_id = linfo->shadow_len++;
sh_data->type_data_id = linfo->cube_len++;
/* Same as linfo->cube_len, no need to save. */
linfo->num_cube_layer++;
}
static void shadow_cube_random_position_set(const EEVEE_Light *evli,
int sample_ofs,
float ws_sample_pos[3])
{
float jitter[3];
#ifdef DEBUG_SHADOW_DISTRIBUTION
int i = 0;
start:
#else
int i = sample_ofs;
#endif
switch ((int)evli->light_type) {
case LA_AREA:
EEVEE_sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
break;
case (int)LAMPTYPE_AREA_ELLIPSE:
EEVEE_sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
break;
default:
EEVEE_sample_ball(i, evli->radius, jitter);
}
#ifdef DEBUG_SHADOW_DISTRIBUTION
float p[3];
add_v3_v3v3(p, jitter, ws_sample_pos);
DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
if (i++ < sample_ofs) {
goto start;
}
#endif
add_v3_v3(ws_sample_pos, jitter);
}
/* Return true if sample has changed and light needs to be updated. */
bool EEVEE_shadows_cube_setup(EEVEE_LightsInfo *linfo, const EEVEE_Light *evli, int sample_ofs)
{
EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
eevee_light_matrix_get(evli, cube_data->shadowmat);
shdw_data->far = max_ff(sqrt(1.0f / evli->invsqrdist), 3e-4);
shdw_data->near = min_ff(shdw_data->near, shdw_data->far - 1e-4);
bool update = false;
if (linfo->soft_shadows) {
shadow_cube_random_position_set(evli, sample_ofs, cube_data->shadowmat[3]);
/* Update if position changes (avoid infinite update if soft shadows does not move).
* Other changes are caught by depsgraph tagging. This one is for update between samples. */
update = !compare_v3v3(cube_data->shadowmat[3], cube_data->position, 1e-10f);
/**
* Anti-Aliasing jitter: Add random rotation.
*
* The 2.0 factor is because texel angular size is not even across the cubemap,
* so we make the rotation range a bit bigger.
* This will not blur the shadow even if the spread is too big since we are just
* rotating the shadow cubemap.
* Note that this may be a rough approximation an may not converge to a perfectly
* smooth shadow (because sample distribution is quite non-uniform) but is enought
* in practice.
**/
/* NOTE: this has implication for spotlight rendering optimization
* (see EEVEE_shadows_draw_cubemap). */
float angular_texel_size = 2.0f * DEG2RADF(90) / (float)linfo->shadow_cube_size;
EEVEE_random_rotation_m4(sample_ofs, angular_texel_size, cube_data->shadowmat);
}
copy_v3_v3(cube_data->position, cube_data->shadowmat[3]);
invert_m4(cube_data->shadowmat);
return update;
}
static void eevee_ensure_cube_views(
float near, float far, int cube_res, const float viewmat[4][4], DRWView *view[6])
{
float winmat[4][4];
float side = near;
/* TODO shadowcube array. */
if (true) {
/* This half texel offset is used to ensure correct filtering between faces. */
/* FIXME: This exhibit float precision issue with lower cube_res.
* But it seems to be caused by the perspective_m4. */
side *= ((float)cube_res + 1.0f) / (float)(cube_res);
}
perspective_m4(winmat, -side, side, -side, side, near, far);
for (int i = 0; i < 6; i++) {
float tmp[4][4];
mul_m4_m4m4(tmp, cubefacemat[i], viewmat);
if (view[i] == NULL) {
view[i] = DRW_view_create(tmp, winmat, NULL, NULL, NULL);
}
else {
DRW_view_update(view[i], tmp, winmat, NULL, NULL);
}
}
}
/* Does a spot angle fits a single cubeface. */
static bool spot_angle_fit_single_face(const EEVEE_Light *evli)
{
/* alpha = spot/cone half angle. */
/* beta = scaled spot/cone half angle. */
float cos_alpha = evli->spotsize;
float sin_alpha = sqrtf(max_ff(0.0f, 1.0f - cos_alpha * cos_alpha));
float cos_beta = min_ff(cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizex),
cos_alpha / hypotf(cos_alpha, sin_alpha * evli->sizey));
/* Don't use 45 degrees because AA jitter can offset the face. */
return cos_beta > cosf(DEG2RADF(42.0f));
}
void EEVEE_shadows_draw_cubemap(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int cube_index)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PrivateData *g_data = stl->g_data;
EEVEE_LightsInfo *linfo = sldata->lights;
EEVEE_Light *evli = linfo->light_data + linfo->shadow_cube_light_indices[cube_index];
EEVEE_Shadow *shdw_data = linfo->shadow_data + (int)evli->shadow_id;
EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + (int)shdw_data->type_data_id;
eevee_ensure_cube_views(shdw_data->near,
shdw_data->far,
linfo->shadow_cube_size,
cube_data->shadowmat,
g_data->cube_views);
/* Render shadow cube */
/* Render 6 faces separately: seems to be faster for the general case.
* The only time it's more beneficial is when the CPU culling overhead
* outweigh the instancing overhead. which is rarely the case. */
for (int j = 0; j < 6; j++) {
/* Optimization: Only render the needed faces. */
/* Skip all but -Z face. */
if (evli->light_type == LA_SPOT && j != 5 && spot_angle_fit_single_face(evli))
continue;
/* Skip +Z face. */
if (evli->light_type != LA_LOCAL && j == 4)
continue;
/* TODO(fclem) some cube sides can be invisible in the main views. Cull them. */
// if (frustum_intersect(g_data->cube_views[j], main_view))
// continue;
DRW_view_set_active(g_data->cube_views[j]);
int layer = cube_index * 6 + j;
GPU_framebuffer_texture_layer_attach(sldata->shadow_fb, sldata->shadow_cube_pool, 0, layer, 0);
GPU_framebuffer_bind(sldata->shadow_fb);
GPU_framebuffer_clear_depth(sldata->shadow_fb, 1.0f);
DRW_draw_pass(psl->shadow_pass);
}
BLI_BITMAP_SET(&linfo->sh_cube_update[0], cube_index, false);
}

View File

@ -38,7 +38,13 @@ static struct {
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_lights_lib_glsl[];
extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_effect_subsurface_frag_glsl[];
extern char datatoc_effect_translucency_frag_glsl[];
static void eevee_create_shader_subsurface(void)
{
@ -46,16 +52,23 @@ static void eevee_create_shader_subsurface(void)
datatoc_common_uniforms_lib_glsl,
datatoc_effect_subsurface_frag_glsl);
/* TODO(fclem) remove some of these dependencies. */
char *frag_translucent_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_bsdf_sampling_lib_glsl,
datatoc_raytrace_lib_glsl,
datatoc_octahedron_lib_glsl,
datatoc_lights_lib_glsl,
datatoc_effect_translucency_frag_glsl);
e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n");
e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str,
"#define SECOND_PASS\n"
"#define USE_SEP_ALBEDO\n");
e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str,
"#define SECOND_PASS\n"
"#define USE_SEP_ALBEDO\n"
"#define RESULT_ACCUM\n");
e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define RESULT_ACCUM\n");
e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_translucent_str,
"#define EEVEE_TRANSLUCENCY\n" SHADER_DEFINES);
MEM_freeN(frag_translucent_str);
MEM_freeN(frag_str);
}
@ -69,7 +82,6 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2;
effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0;
common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold;
}
@ -90,9 +102,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
effects->sss_stencil = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_DEPTH24_STENCIL8, &draw_engine_eevee_type);
effects->sss_blur = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type);
effects->sss_data = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_RGBA16F, &draw_engine_eevee_type);
fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
effects->sss_irradiance = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
effects->sss_radius = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_R16F, &draw_engine_eevee_type);
effects->sss_albedo = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
GPUTexture *stencil_tex = effects->sss_stencil;
@ -115,15 +131,13 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
{GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(txl->color)});
GPU_framebuffer_ensure_config(
&fbl->sss_clear_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(effects->sss_data)});
&fbl->sss_translucency_fb,
{GPU_ATTACHMENT_TEXTURE(stencil_tex), GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance)});
if (effects->sss_separate_albedo) {
effects->sss_albedo = DRW_texture_pool_query_2d(
fs_size[0], fs_size[1], GPU_R11F_G11F_B10F, &draw_engine_eevee_type);
}
else {
effects->sss_albedo = NULL;
}
GPU_framebuffer_ensure_config(&fbl->sss_clear_fb,
{GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance),
GPU_ATTACHMENT_TEXTURE(effects->sss_radius)});
}
else {
/* Cleanup to release memory */
@ -132,7 +146,8 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb);
effects->sss_stencil = NULL;
effects->sss_blur = NULL;
effects->sss_data = NULL;
effects->sss_irradiance = NULL;
effects->sss_radius = NULL;
}
}
@ -202,6 +217,7 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
DRW_PASS_CREATE(psl->sss_blur_ps, state);
DRW_PASS_CREATE(psl->sss_resolve_ps, state | DRW_STATE_BLEND_ADD);
DRW_PASS_CREATE(psl->sss_accum_ps, state | DRW_STATE_BLEND_ADD);
DRW_PASS_CREATE(psl->sss_translucency_ps, state | DRW_STATE_BLEND_ADD);
}
void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
@ -219,42 +235,66 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_data);
DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance);
DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1];
grp = DRW_shgroup_create(sh, psl->sss_resolve_ps);
grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur);
DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
if (effects->sss_separate_albedo) {
DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
}
if (DRW_state_is_image_render()) {
grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps);
grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_accum_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur);
DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
if (effects->sss_separate_albedo) {
DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
}
}
}
void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile,
GPUTexture *sss_tex_profile)
{
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth;
DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_translucency_ps);
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_stencil_mask(grp, sss_id);
DRW_shgroup_call(grp, quad, NULL);
}
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
@ -273,7 +313,8 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_TEXTURE(effects->sss_data),
GPU_ATTACHMENT_TEXTURE(effects->sss_irradiance),
GPU_ATTACHMENT_TEXTURE(effects->sss_radius),
GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
@ -287,11 +328,12 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_LEAVE,
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE});
}
}
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;
@ -313,6 +355,28 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT);
}
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);
/* Reset original state. */
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);
}
/* 1. horizontal pass */
GPU_framebuffer_bind(fbl->sss_blur_fb);
GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear);

View File

@ -595,7 +595,7 @@ void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
effects->volume_transmit = e_data.dummy_transmit;
}
void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
@ -605,6 +605,15 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
DRW_stats_group_start("Volumetrics");
/* 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);
GPU_framebuffer_bind(fbl->volumetric_fb);
DRW_draw_pass(psl->volumetric_world_ps);
DRW_draw_pass(psl->volumetric_objects_ps);

View File

@ -56,12 +56,12 @@ struct LightData {
#endif
struct ShadowData {
vec4 near_far_bias_exp;
vec4 shadow_data_start_end;
vec4 near_far_bias_id;
vec4 contact_shadow_data;
};
struct ShadowCubeData {
mat4 shadowmat;
vec4 position;
};
@ -69,22 +69,20 @@ struct ShadowCascadeData {
mat4 shadowmat[MAX_CASCADE_NUM];
vec4 split_start_distances;
vec4 split_end_distances;
vec4 shadow_vec_id;
};
/* convenience aliases */
#define sh_near near_far_bias_exp.x
#define sh_far near_far_bias_exp.y
#define sh_bias near_far_bias_exp.z
#define sh_exp near_far_bias_exp.w
#define sh_bleed near_far_bias_exp.w
#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_near near_far_bias_id.x
#define sh_far near_far_bias_id.y
#define sh_bias near_far_bias_id.z
#define sh_data_index near_far_bias_id.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
#define sh_contact_thickness contact_shadow_data.w
#define sh_shadow_vec shadow_vec_id.xyz
#define sh_tex_index shadow_vec_id.w
/* ------- Convenience functions --------- */
@ -777,10 +775,9 @@ struct Closure {
vec3 transmittance;
float holdout;
# ifdef USE_SSS
vec4 sss_data;
# ifdef USE_SSS_ALBEDO
vec3 sss_irradiance;
vec3 sss_albedo;
# endif
float sss_radius;
# endif
vec4 ssr_data;
vec2 ssr_normal;
@ -796,13 +793,8 @@ Closure nodetree_exec(void); /* Prototype */
# define CLOSURE_HOLDOUT_FLAG 4
# ifdef USE_SSS
# ifdef USE_SSS_ALBEDO
# define CLOSURE_DEFAULT \
Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), 0)
# else
# define CLOSURE_DEFAULT \
Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec4(0.0), vec2(0.0), 0)
# endif
# define CLOSURE_DEFAULT \
Closure(vec3(0.0), vec3(0.0), 0.0, vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# else
# define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), 0.0, vec4(0.0), vec2(0.0), 0)
# endif
@ -823,30 +815,22 @@ void closure_load_ssr_data(
}
}
# ifdef USE_SSS
void closure_load_sss_data(float radius,
vec3 sss_radiance,
# ifdef USE_SSS_ALBEDO
vec3 sss_albedo,
# endif
int sss_id,
inout Closure cl)
void closure_load_sss_data(
float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl)
{
# ifdef USE_SSS
if (sss_id == outputSssId) {
cl.sss_data = vec4(sss_radiance, radius);
# ifdef USE_SSS_ALBEDO
cl.sss_irradiance = sss_irradiance;
cl.sss_radius = radius;
cl.sss_albedo = sss_albedo;
# endif
cl.flag |= CLOSURE_SSS_FLAG;
}
else {
cl.radiance += sss_radiance;
# ifdef USE_SSS_ALBEDO
cl.radiance += sss_radiance * sss_albedo;
# endif
else
# endif
{
cl.radiance += sss_irradiance * sss_albedo;
}
}
# endif
Closure closure_mix(Closure cl1, Closure cl2, float fac)
{
@ -862,13 +846,11 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac)
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
cl.sss_data = mix(cl1.sss_data, cl2.sss_data, fac);
cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac);
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
/* It also does not make sense to mix SSS radius or albedo. */
cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
# ifdef USE_SSS_ALBEDO
cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
# endif
/* It also does not make sense to mix SSS radius or irradiance. */
cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
# endif
return cl;
}
@ -887,13 +869,11 @@ Closure closure_add(Closure cl1, Closure cl2)
cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
# ifdef USE_SSS
cl.sss_data = cl1.sss_data + cl2.sss_data;
cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo;
bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
/* It also does not make sense to mix SSS radius or albedo. */
cl.sss_data.w = (use_cl1_sss) ? cl1.sss_data.w : cl2.sss_data.w;
# ifdef USE_SSS_ALBEDO
cl.sss_albedo = (use_cl1_sss) ? cl1.sss_albedo : cl2.sss_albedo;
# endif
/* It also does not make sense to mix SSS radius or irradiance. */
cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
# endif
return cl;
}
@ -914,10 +894,9 @@ layout(location = 0) out vec4 outRadiance;
layout(location = 1) out vec2 ssrNormals;
layout(location = 2) out vec4 ssrData;
# ifdef USE_SSS
layout(location = 3) out vec4 sssData;
# ifdef USE_SSS_ALBEDO
layout(location = 4) out vec4 sssAlbedo;
# endif
layout(location = 3) out vec3 sssIrradiance;
layout(location = 4) out float sssRadius;
layout(location = 5) out vec3 sssAlbedo;
# endif
# else /* USE_ALPHA_BLEND */
/* Use dual source blending to be able to make a whole range of effects. */
@ -953,10 +932,9 @@ void main()
ssrNormals = cl.ssr_normal;
ssrData = cl.ssr_data;
# ifdef USE_SSS
sssData = cl.sss_data;
# ifdef USE_SSS_ALBEDO
sssAlbedo = cl.sss_albedo.rgbb;
# endif
sssIrradiance = cl.sss_irradiance;
sssRadius = cl.sss_radius;
sssAlbedo = cl.sss_albedo;
# endif
# endif
@ -964,6 +942,8 @@ void main()
# ifdef USE_SSS
float fac = float(!sssToggle);
/* TODO(fclem) we shouldn't need this.
* Just disable USE_SSS when USE_REFRACTION is enabled. */
# ifdef USE_REFRACTION
/* SSRefraction pass is done after the SSS pass.
* In order to not loose the diffuse light totally we
@ -971,11 +951,7 @@ void main()
fac = 1.0;
# endif
# ifdef USE_SSS_ALBEDO
outRadiance.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * fac;
# else
outRadiance.rgb += cl.sss_data.rgb * fac;
# endif
outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
# endif
}

View File

@ -31,7 +31,7 @@ Closure nodetree_exec(void)
vec3 f0 = mix(dielectric, basecol, metallic);
vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic);
vec3 out_diff, out_spec, ssr_spec;
eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
eevee_closure_default(N, albedo, f0, f90, 1, roughness, 1.0, true, out_diff, out_spec, ssr_spec);
Closure cl = CLOSURE_DEFAULT;
cl.radiance = out_spec + out_diff * albedo;

View File

@ -10,7 +10,8 @@ layout(std140) uniform sssProfile
};
uniform sampler2D depthBuffer;
uniform sampler2D sssData;
uniform sampler2D sssIrradiance;
uniform sampler2D sssRadius;
uniform sampler2D sssAlbedo;
#ifndef UTIL_TEX
@ -19,9 +20,12 @@ uniform sampler2DArray utilTex;
# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
layout(location = 0) out vec4 FragColor;
#ifdef RESULT_ACCUM
/* Render Passes Accumulation */
layout(location = 0) out vec4 sssDirect;
layout(location = 1) out vec4 sssColor;
#else
layout(location = 0) out vec4 sssRadiance;
#endif
float get_view_z_from_depth(float depth)
@ -43,7 +47,8 @@ void main(void)
{
vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */
vec2 uvs = gl_FragCoord.xy * pixel_size;
vec4 sss_data = texture(sssData, uvs).rgba;
vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb;
float sss_radius = texture(sssRadius, uvs).r;
float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r);
float rand = texelfetch_noise_tex(gl_FragCoord.xy).r;
@ -58,44 +63,36 @@ void main(void)
/* Compute kernel bounds in 2D. */
float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3];
vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_data.aa / homcoord;
vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_radius / homcoord;
vec2 finalStep = scale * radii_max_radius.w;
finalStep *= 0.5; /* samples range -1..1 */
/* Center sample */
vec3 accum = sss_data.rgb * kernel[0].rgb;
vec3 accum = sss_irradiance * kernel[0].rgb;
for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) {
vec2 sample_uv = uvs + kernel[i].a * finalStep *
((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand);
vec3 color = texture(sssData, sample_uv).rgb;
vec3 color = texture(sssIrradiance, sample_uv).rgb;
float sample_depth = texture(depthBuffer, sample_uv).r;
sample_depth = get_view_z_from_depth(sample_depth);
/* Depth correction factor. */
float depth_delta = depth_view - sample_depth;
float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_data.a)), 0.0, 1.0);
float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0);
/* Out of view samples. */
if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) {
s = 1.0;
}
accum += kernel[i].rgb * mix(color, sss_data.rgb, s);
/* Mix with first sample in failure case and apply kernel color. */
accum += kernel[i].rgb * mix(color, sss_irradiance, s);
}
#ifdef FIRST_PASS
FragColor = vec4(accum, sss_data.a);
#ifdef RESULT_ACCUM
sssDirect = vec4(accum, 1.0);
sssColor = vec4(texture(sssAlbedo, uvs).rgb, 1.0);
#elif defined(FIRST_PASS)
sssRadiance = vec4(accum, 1.0);
#else /* SECOND_PASS */
# ifdef USE_SEP_ALBEDO
# ifdef RESULT_ACCUM
FragColor = vec4(accum, 1.0);
sssColor = texture(sssAlbedo, uvs);
# else
FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
# endif
# else
FragColor = vec4(accum, 1.0);
# endif
sssRadiance = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
#endif
}

View File

@ -0,0 +1,165 @@
in vec4 uvcoordsvar;
out vec4 FragColor;
uniform sampler1D sssTexProfile;
uniform sampler2D sssRadius;
uniform sampler2DArray sssShadowCubes;
uniform sampler2DArray sssShadowCascades;
#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;
};
vec3 sss_profile(float s)
{
s /= radii_max_radius.w;
return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
}
#ifndef UTIL_TEX
# define UTIL_TEX
uniform sampler2DArray utilTex;
# define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
#endif /* UTIL_TEX */
float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
{
float power, falloff;
/* XXX : Removing Area Power. */
/* TODO : put this out of the shader. */
if (ld.l_type >= AREA_RECT) {
power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
if (ld.l_type == AREA_ELLIPSE) {
power *= M_PI * 0.25;
}
power *= 0.3 * 20.0 *
max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
power /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
else if (ld.l_type == SUN) {
power = 1.0 / (1.0 + (ld.l_radius * ld.l_radius * 0.5));
power *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
power *= M_2PI * 0.78; /* Matching cycles with point light. */
power *= 0.082; /* XXX ad hoc, empirical */
falloff = dot(N, -ld.l_forward);
}
else {
power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
power *= 1.5; /* XXX ad hoc, empirical */
power /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
/* No transmittance at grazing angle (hide artifacts) */
return power * saturate(falloff * 2.0);
}
/* Some driver poorly optimize this code. Use direct reference to matrices. */
#define sd(x) shadows_data[x]
#define scube(x) shadows_cube_data[x]
#define scascade(x) shadows_cascade_data[x]
vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale)
{
int shadow_id = int(ld.l_shadowid);
vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
/* TODO(fclem) do something better than this. */
// vec3 T, B;
// make_orthonormal_basis(L.xyz / L.w, T, B);
// rand.xy *= data.sh_blur;
// W = W + T * rand.x + B * rand.y;
float s, dist;
int data_id = int(sd(shadow_id).sh_data_index);
if (ld.l_type == SUN) {
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
vec4 weights = step(scascade(data_id).split_end_distances, view_z);
float id = abs(4.0 - dot(weights, weights));
if (id > 3.0) {
return vec3(0.0);
}
/* Same factor as in get_cascade_world_distance(). */
float range = abs(sd(shadow_id).sh_far - sd(shadow_id).sh_near);
vec4 shpos = scascade(data_id).shadowmat[int(id)] * vec4(W, 1.0);
dist = shpos.z * range;
if (shpos.z > 1.0 || shpos.z < 0.0) {
return vec3(0.0);
}
float tex_id = scascade(data_id).sh_tex_index;
s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r;
s *= range;
}
else {
vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
dist = length(cubevec);
cubevec /= dist;
/* tex_id == data_id for cube shadowmap */
float tex_id = float(data_id);
s = sample_cube(sssShadowCubes, cubevec, tex_id).r;
s = length(cubevec / max_v3(abs(cubevec))) *
linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
}
float delta = dist - s;
float power = light_translucent_power_with_falloff(ld, N, l_vector);
return power * sss_profile(abs(delta) / sss_scale);
}
#undef sd
#undef scube
#undef scsmd
void main(void)
{
vec2 uvs = uvcoordsvar.xy;
float sss_scale = texture(sssRadius, uvs).r;
vec3 W = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r);
vec3 N = normalize(cross(dFdx(W), dFdy(W)));
vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy;
rand.xy *= fast_sqrt(rand.z);
vec3 accum = vec3(0.0);
for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
LightData ld = lights_data[i];
/* Only shadowed light can produce translucency */
if (ld.l_shadowid < 0.0) {
continue;
}
vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
l_vector.xyz = ld.l_position - W;
l_vector.w = length(l_vector.xyz);
float att = light_attenuation(ld, l_vector);
if (att < 1e-8) {
continue;
}
accum += att * ld.l_color * light_translucent(ld, W, -N, l_vector, rand.xy, sss_scale);
}
FragColor = vec4(accum, 1.0);
}

View File

@ -1,6 +1,6 @@
uniform sampler2DArray shadowCubeTexture;
uniform sampler2DArray shadowCascadeTexture;
uniform sampler2DArrayShadow shadowCubeTexture;
uniform sampler2DArrayShadow shadowCascadeTexture;
#define LAMPS_LIB
@ -24,129 +24,115 @@ layout(std140) uniform light_block
/* Used to define the area light shape, doesn't directly correspond to a Blender light type. */
#define AREA_ELLIPSE 100.0
#if defined(SHADOW_VSM)
# define ShadowSample vec2
# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg
# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg
#elif defined(SHADOW_ESM)
# define ShadowSample float
# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
#else
# define ShadowSample float
# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
#endif
#if defined(SHADOW_VSM)
# define get_depth_delta(dist, s) (dist - s.x)
#else
# define get_depth_delta(dist, s) (dist - s)
#endif
/* ----------------------------------------------------------- */
/* ----------------------- Shadow tests ---------------------- */
/* ----------------------------------------------------------- */
#if defined(SHADOW_VSM)
float shadow_test(ShadowSample moments, float dist, ShadowData sd)
float cubeFaceIndexEEVEE(vec3 P)
{
float p = 0.0;
if (dist <= moments.x) {
p = 1.0;
vec3 aP = abs(P);
if (all(greaterThan(aP.xx, aP.yz))) {
return (P.x > 0.0) ? 0.0 : 1.0;
}
float variance = moments.y - (moments.x * moments.x);
variance = max(variance, sd.sh_bias / 10.0);
float d = moments.x - dist;
float p_max = variance / (variance + d * d);
/* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
p_max = clamp((p_max - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0);
return max(p, p_max);
}
#elif defined(SHADOW_ESM)
float shadow_test(ShadowSample z, float dist, ShadowData sd)
{
return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias)));
}
#else
float shadow_test(ShadowSample z, float dist, ShadowData sd)
{
return step(0, z - dist + sd.sh_bias);
}
#endif
/* ----------------------------------------------------------- */
/* ----------------------- Shadow types ---------------------- */
/* ----------------------------------------------------------- */
float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
{
vec3 cubevec = W - scd.position.xyz;
float dist = length(cubevec);
cubevec /= dist;
ShadowSample s = sample_cube(cubevec, texid);
return shadow_test(s, dist, sd);
}
float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid)
{
vec4 shpos = shadowmat * vec4(W, 1.0);
float dist = shpos.z * range;
ShadowSample s = sample_cascade(shpos.xy, texid);
float vis = shadow_test(s, dist, sd);
/* If fragment is out of shadowmap range, do not occlude */
if (shpos.z < 1.0 && shpos.z > 0.0) {
return vis;
else if (all(greaterThan(aP.yy, aP.xz))) {
return (P.y > 0.0) ? 2.0 : 3.0;
}
else {
return 1.0;
return (P.z > 0.0) ? 4.0 : 5.0;
}
}
float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W)
vec2 cubeFaceCoordEEVEE(vec3 P, float face, float scale)
{
if (face < 2.0) {
return (P.zy / P.x) * scale * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
}
else if (face < 4.0) {
return (P.xz / P.y) * scale * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
}
else {
return (P.xy / P.z) * scale * vec2(0.5, -sign(P.z) * 0.5) + 0.5;
}
}
vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArray tex)
{
/* Scaling to compensate the 1px border around the face. */
float cube_res = float(textureSize(tex, 0).x);
float scale = (cube_res) / (cube_res + 1.0);
return cubeFaceCoordEEVEE(P, face, scale);
}
vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
{
/* Scaling to compensate the 1px border around the face. */
float cube_res = float(textureSize(tex, 0).x);
float scale = (cube_res) / (cube_res + 1.0);
return cubeFaceCoordEEVEE(P, face, scale);
}
vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
{
/* Manual Shadow Cube Layer indexing. */
/* TODO Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);
vec3 coord = vec3(uv, cube * 6.0 + face);
return texture(tex, coord);
}
vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id)
{
return texture(tex, vec3(co, cascade_id));
}
/* Some driver poorly optimize this code. Use direct reference to matrices. */
#define sd(x) shadows_data[x]
#define scube(x) shadows_cube_data[x]
#define scascade(x) shadows_cascade_data[x]
float sample_cube_shadow(int shadow_id, vec3 W)
{
int data_id = int(sd(shadow_id).sh_data_index);
vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
float dist = max_v3(abs(cubevec)) - sd(shadow_id).sh_bias;
dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
/* Manual Shadow Cube Layer indexing. */
/* TODO Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
vec2 coord = cubeFaceCoordEEVEE(cubevec, face, shadowCubeTexture);
/* tex_id == data_id for cube shadowmap */
float tex_id = float(data_id);
return texture(shadowCubeTexture, vec4(coord, tex_id * 6.0 + face, dist));
}
float sample_cascade_shadow(int shadow_id, vec3 W)
{
int data_id = int(sd(shadow_id).sh_data_index);
float tex_id = scascade(data_id).sh_tex_index;
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
vec4 weights = smoothstep(shadows_cascade_data[scd_id].split_end_distances,
shadows_cascade_data[scd_id].split_start_distances.yzwx,
view_z);
vec4 weights = 1.0 - smoothstep(scascade(data_id).split_end_distances,
scascade(data_id).split_start_distances.yzwx,
view_z);
float tot_weight = dot(weights.xyz, vec3(1.0));
weights.yzw -= weights.xyz;
int cascade = int(clamp(tot_weight, 0.0, 3.0));
float blend = fract(tot_weight);
float vis = weights.w;
vec4 coord, shpos;
/* Main cascade. */
shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
vis += texture(shadowCascadeTexture, coord) * (1.0 - blend);
vec4 vis = vec4(1.0);
float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */
cascade = min(3, cascade + 1);
/* Second cascade. */
shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
vis += texture(shadowCascadeTexture, coord) * blend;
/* 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], W, range, texid + 0);
vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1);
vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2);
vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3);
float weight_sum = dot(vec4(1.0), weights);
if (weight_sum > 0.9999) {
float vis_sum = dot(vec4(1.0), vis * weights);
return vis_sum / weight_sum;
}
else {
float vis_sum = dot(vec4(1.0), vis * step(0.001, weights));
return mix(1.0, vis_sum, weight_sum);
}
return saturate(vis);
}
#undef sd
#undef scube
#undef scsmd
/* ----------------------------------------------------------- */
/* --------------------- Light Functions --------------------- */
@ -173,16 +159,9 @@ float spot_attenuation(LightData ld, vec3 l_vector)
return spotmask;
}
float light_visibility(LightData ld,
vec3 W,
#ifndef VOLUMETRICS
vec3 viewPosition,
vec3 vN,
#endif
vec4 l_vector)
float light_attenuation(LightData ld, vec4 l_vector)
{
float vis = 1.0;
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
@ -192,69 +171,66 @@ float light_visibility(LightData ld,
if (ld.l_type != SUN) {
vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
}
return vis;
}
float light_visibility(LightData ld,
vec3 W,
#ifndef VOLUMETRICS
vec3 viewPosition,
float tracing_depth,
vec3 true_normal,
float rand_x,
const bool use_contact_shadows,
#endif
vec4 l_vector)
{
float vis = light_attenuation(ld, l_vector);
#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
/* shadowing */
if (ld.l_shadowid >= 0.0 && vis > 0.001) {
ShadowData data = shadows_data[int(ld.l_shadowid)];
if (ld.l_type == SUN) {
vis *= shadow_cascade(data, int(data.sh_data_start), data.sh_tex_start, W);
vis *= sample_cascade_shadow(int(ld.l_shadowid), W);
}
else {
vis *= shadow_cubemap(
data, shadows_cube_data[int(data.sh_data_start)], data.sh_tex_start, W);
vis *= sample_cube_shadow(int(ld.l_shadowid), W);
}
# ifndef VOLUMETRICS
ShadowData sd = shadows_data[int(ld.l_shadowid)];
/* Only compute if not already in shadow. */
if (data.sh_contact_dist > 0.0) {
vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) :
data.sh_contact_dist;
if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) {
/* Contact Shadows. */
vec3 ray_ori, ray_dir;
float trace_distance;
vec3 T, B;
make_orthonormal_basis(L.xyz / L.w, T, B);
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread;
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
vec3 ray_dir = L.xyz + T * rand.z + B * rand.w;
ray_dir = transform_direction(ViewMatrix, ray_dir);
ray_dir = normalize(ray_dir);
vec3 ray_ori = viewPosition;
/* Fix translucency shadowed by contact shadows. */
vN = (gl_FrontFacing) ? vN : -vN;
if (dot(vN, ray_dir) <= 0.0) {
return vis;
if (ld.l_type == SUN) {
trace_distance = sd.sh_contact_dist;
ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance;
}
else {
ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W;
float len = length(ray_dir);
trace_distance = min(sd.sh_contact_dist, len);
ray_dir *= trace_distance / len;
}
float bias = 0.5; /* Constant Bias */
bias += 1.0 - abs(dot(vN, ray_dir)); /* Angle dependent bias */
bias *= gl_FrontFacing ? data.sh_contact_offset : -data.sh_contact_offset;
vec3 nor_bias = vN * bias;
ray_ori += nor_bias;
ray_dir *= trace_distance;
ray_dir -= nor_bias;
ray_dir = transform_direction(ViewMatrix, ray_dir);
ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset;
vec3 hit_pos = raycast(
-1, ray_ori, ray_dir, data.sh_contact_thickness, rand.x, 0.1, 0.001, false);
-1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false);
if (hit_pos.z > 0.0) {
hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
float hit_dist = distance(viewPosition, hit_pos);
float dist_ratio = hit_dist / trace_distance;
return vis * saturate(dist_ratio * dist_ratio * dist_ratio);
return vis * saturate(dist_ratio * 3.0 - 2.0);
}
}
# endif
# endif /* VOLUMETRICS */
}
#endif
@ -325,134 +301,3 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
}
}
#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))
#ifdef USE_TRANSLUCENCY
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;
}
#endif
vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
{
#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
return vec3(0.0);
#else
vec3 vis = vec3(1.0);
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
if (ld.l_type >= SPOT) {
vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
}
if (ld.l_type != SUN) {
vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
}
/* Only shadowed light can produce translucency */
if (ld.l_shadowid >= 0.0 && vis.x > 0.001) {
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);
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
rand.zw *= fast_sqrt(rand.y) * 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.z + B * rand.w;
if (ld.l_type == SUN) {
int scd_id = int(data.sh_data_start);
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z);
float id = abs(4.0 - dot(weights, weights));
if (id > 3.0) {
return vec3(0.0);
}
/* Same factor as in get_cascade_world_distance(). */
float range = abs(data.sh_far - data.sh_near);
vec4 shpos = shadows_cascade_data[scd_id].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);
}
ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id);
delta = get_depth_delta(dist, s);
}
else {
vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz;
float dist = length(cubevec);
cubevec /= dist;
ShadowSample s = sample_cube(cubevec, data.sh_tex_start);
delta = get_depth_delta(dist, s);
}
/* XXX : Removing Area Power. */
/* TODO : put this out of the shader. */
float falloff;
if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
if (ld.l_type == AREA_ELLIPSE) {
vis *= M_PI * 0.25;
}
vis *= 0.3 * 20.0 *
max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
vis /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
else if (ld.l_type == SUN) {
vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
vis *= M_2PI * 0.78; /* Matching cycles with point light. */
vis *= 0.082; /* XXX ad hoc, empirical */
falloff = dot(N, -ld.l_forward);
}
else {
vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
vis *= 1.5; /* XXX ad hoc, empirical */
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);
}
else {
vis = vec3(0.0);
}
return vis;
#endif
}

View File

@ -144,14 +144,12 @@ void CLOSURE_NAME(vec3 N
,
float ior
#endif
,
const bool use_contact_shadows
#ifdef CLOSURE_DIFFUSE
,
out vec3 out_diff
#endif
#ifdef CLOSURE_SUBSURFACE
,
out vec3 out_trans
#endif
#ifdef CLOSURE_GLOSSY
,
out vec3 out_spec
@ -170,10 +168,6 @@ void CLOSURE_NAME(vec3 N
out_diff = vec3(0.0);
#endif
#ifdef CLOSURE_SUBSURFACE
out_trans = vec3(0.0);
#endif
#ifdef CLOSURE_GLOSSY
out_spec = vec3(0.0);
#endif
@ -230,6 +224,16 @@ void CLOSURE_NAME(vec3 N
vec3 out_spec_clear = vec3(0.0);
# endif
float tracing_depth = gl_FragCoord.z;
/* Constant bias (due to depth buffer precision) */
/* Magic numbers for 24bits of precision.
* From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
/* Convert to view Z. */
tracing_depth = get_view_z_from_depth(tracing_depth);
vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
LightData ld = lights_data[i];
@ -237,7 +241,14 @@ void CLOSURE_NAME(vec3 N
l_vector.xyz = ld.l_position - worldPosition;
l_vector.w = length(l_vector.xyz);
float l_vis = light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
float l_vis = light_visibility(ld,
worldPosition,
viewPosition,
tracing_depth,
true_normal,
rand.x,
use_contact_shadows,
l_vector);
if (l_vis < 1e-8) {
continue;
@ -249,10 +260,6 @@ void CLOSURE_NAME(vec3 N
out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
# endif
# ifdef CLOSURE_SUBSURFACE
out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale);
# endif
# ifdef CLOSURE_GLOSSY
out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
# endif
@ -441,10 +448,17 @@ void CLOSURE_NAME(vec3 N
/* Ambient Occlusion */
/* ---------------------------- */
# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
/* HACK: Fix for translucent BSDF. (see T65631) */
bool same_side = dot((gl_FrontFacing) ? worldNormal : -worldNormal, N) > 0.0;
if (!use_contact_shadows) {
/* HACK: Fix for translucent BSDF. (see T65631) */
N = -N;
}
vec3 bent_normal;
float final_ao = occlusion_compute(same_side ? N : -N, viewPosition, ao, rand, bent_normal);
float final_ao = occlusion_compute(gl_FrontFacing ? N : -N, viewPosition, ao, rand, bent_normal);
if (!use_contact_shadows) {
N = -N;
/* Bypass bent normal. */
bent_normal = N;
}
# endif
/* ---------------------------- */

View File

@ -120,7 +120,8 @@ void prepare_raycast(vec3 ray_origin,
ss_ray = ss_start * m.xyyy + 0.5;
ss_step *= m.xyyy;
ss_ray.xy += m * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */
/* take the center of the texel. */
// ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset);
}
/* See times_and_deltas. */

View File

@ -1,199 +0,0 @@
/* Copy the depth only shadowmap into another texture while converting
* to linear depth (or other storage method) and doing a 3x3 box filter. */
layout(std140) uniform shadow_render_block
{
/* Use vectors to avoid alignment padding. */
ivec4 shadowSampleCount;
vec4 shadowInvSampleCount;
vec4 filterSize;
int viewCount;
int baseId;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float exponent;
};
#ifdef CSM
uniform sampler2DArray shadowTexture;
#else
uniform samplerCube shadowTexture;
#endif
flat in int layerID;
#ifdef CSM
# define cascadeID layerID
#else
# define cascadeID 0
#endif
out vec4 FragColor;
#define linear_depth(z) \
((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip))
/* add bias so background filtering does not bleed into shadow map */
#define BACKGROUND_BIAS 0.05
#ifdef CSM
vec4 get_world_distance(vec4 depths, vec3 cos[4])
{
depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS;
return clamp(
depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
}
float get_world_distance(float depth, vec3 cos)
{
depth += step(0.9999, depth) * BACKGROUND_BIAS;
return clamp(
depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
}
#else /* CUBEMAP */
vec4 get_world_distance(vec4 depths, vec3 cos[4])
{
depths = linear_depth(depths);
cos[0] = normalize(abs(cos[0]));
cos[1] = normalize(abs(cos[1]));
cos[2] = normalize(abs(cos[2]));
cos[3] = normalize(abs(cos[3]));
vec4 cos_vec;
cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z));
cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z));
cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z));
cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z));
return depths / cos_vec;
}
float get_world_distance(float depth, vec3 cos)
{
depth = linear_depth(depth);
cos = normalize(abs(cos));
float cos_vec = max(cos.x, max(cos.y, cos.z));
return depth / cos_vec;
}
#endif
/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
#define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum))
#define SAMPLE_WEIGHT 0.11111
#ifdef ESM
void prefilter(vec4 depths, float ref, inout float accum)
{
accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0));
}
#else /* VSM */
void prefilter(vec4 depths, float ref, inout vec2 accum)
{
vec4 depths_sqr = depths * depths;
accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT;
}
#endif
#ifdef CSM
vec3 get_texco(vec2 uvs, vec2 ofs)
{
return vec3(uvs + ofs, float(cascadeID));
}
#else /* CUBEMAP */
const vec3 minorAxisX[6] = vec3[6](vec3(0.0f, 0.0f, -1.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(-1.0f, 0.0f, 0.0f));
const vec3 minorAxisY[6] = vec3[6](vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(0.0f, 0.0f, -1.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f));
const vec3 majorAxis[6] = vec3[6](vec3(1.0f, 0.0f, 0.0f),
vec3(-1.0f, 0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(0.0f, 0.0f, -1.0f));
vec3 get_texco(vec2 uvs, vec2 ofs)
{
uvs += ofs;
return majorAxis[layerID] + uvs.x * minorAxisX[layerID] + uvs.y * minorAxisY[layerID];
}
#endif
void main()
{
/* Copy the depth only shadowmap into another texture while converting
* to linear depth and do a 3x3 box blur. */
#ifdef CSM
vec2 uvs = gl_FragCoord.xy * storedTexelSize;
#else /* CUBEMAP */
vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0;
#endif
/* Center texel */
vec3 co = get_texco(uvs, vec2(0.0));
float depth = texture(shadowTexture, co).r;
depth = get_world_distance(depth, co);
if (filterSize[cascadeID] == 0.0) {
#ifdef ESM
FragColor = vec4(depth);
#else /* VSM */
FragColor = vec2(depth, depth * depth).xyxy;
#endif
return;
}
#ifdef ESM
float ref = depth;
float accum = 1.0;
#else /* VSM */
float ref = 0.0; /* UNUSED */
vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT;
#endif
vec3 ofs = vec3(1.0, 0.0, -1.0) * filterSize[cascadeID];
vec3 cos[4];
cos[0] = get_texco(uvs, ofs.zz);
cos[1] = get_texco(uvs, ofs.yz);
cos[2] = get_texco(uvs, ofs.xz);
cos[3] = get_texco(uvs, ofs.zy);
vec4 depths;
depths.x = texture(shadowTexture, cos[0]).r;
depths.y = texture(shadowTexture, cos[1]).r;
depths.z = texture(shadowTexture, cos[2]).r;
depths.w = texture(shadowTexture, cos[3]).r;
depths = get_world_distance(depths, cos);
prefilter(depths, ref, accum);
cos[0] = get_texco(uvs, ofs.xy);
cos[1] = get_texco(uvs, ofs.zx);
cos[2] = get_texco(uvs, ofs.yx);
cos[3] = get_texco(uvs, ofs.xx);
depths.x = texture(shadowTexture, cos[0]).r;
depths.y = texture(shadowTexture, cos[1]).r;
depths.z = texture(shadowTexture, cos[2]).r;
depths.w = texture(shadowTexture, cos[3]).r;
depths = get_world_distance(depths, cos);
prefilter(depths, ref, accum);
#ifdef ESM
accum = ln_space_prefilter_finalize(ref, accum);
#endif
/* Clamp infinite sum. */
FragColor = vec2(clamp(accum, 0.0, 1e16)).xyxy;
}

View File

@ -1,36 +0,0 @@
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
layout(std140) uniform shadow_render_block
{
/* Use vectors to avoid alignment padding. */
ivec4 shadowSampleCount;
vec4 shadowInvSampleCount;
vec4 filterSize;
int viewCount;
int baseId;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float exponent;
};
in int layerID_g[];
flat out int layerID;
void main()
{
gl_Layer = layerID_g[0];
layerID = gl_Layer - baseId;
gl_Position = gl_in[0].gl_Position;
EmitVertex();
gl_Position = gl_in[1].gl_Position;
EmitVertex();
gl_Position = gl_in[2].gl_Position;
EmitVertex();
EndPrimitive();
}

View File

@ -1,32 +0,0 @@
layout(std140) uniform shadow_render_block
{
/* Use vectors to avoid alignment padding. */
ivec4 shadowSampleCount;
vec4 shadowInvSampleCount;
vec4 filterSize;
int viewCount;
int baseId;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float exponent;
};
out int layerID_g;
void main()
{
int v = gl_VertexID % 3;
layerID_g = gl_VertexID / 3;
float x = -1.0 + float((v & 1) << 2);
float y = -1.0 + float((v & 2) << 1);
gl_Position = vec4(x, y, 1.0, 1.0);
/* HACK avoid changing drawcall parameters. */
if (layerID_g >= viewCount) {
gl_Position = vec4(0.0);
}
layerID_g += baseId;
}

View File

@ -1,322 +0,0 @@
layout(std140) uniform shadow_render_block
{
/* Use vectors to avoid alignment padding. */
ivec4 shadowSampleCount;
vec4 shadowInvSampleCount;
vec4 filterSize;
int viewCount;
int baseId;
float cubeTexelSize;
float storedTexelSize;
float nearClip;
float farClip;
float exponent;
};
#ifdef CSM
uniform sampler2DArray shadowTexture;
#else
uniform samplerCube shadowTexture;
#endif
flat in int layerID;
#ifdef CSM
# define cascadeID layerID
#else
# define cascadeID 0
#endif
out vec4 FragColor;
vec3 octahedral_to_cubemap_proj(vec2 co)
{
co = co * 2.0 - 1.0;
vec2 abs_co = abs(co);
vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
if (abs_co.x + abs_co.y > 1.0) {
v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
}
return v;
}
/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
/* http://advances.realtimerendering.com/s2009/SIGGRAPH%202009%20-%20Lighting%20Research%20at%20Bungie.pdf
* Slide 55. */
#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
#define ln_space_prefilter_finalize(ref, sum) (ref + log(shadowInvSampleCount[cascadeID] * sum))
#ifdef CSM
vec3 get_texco(vec3 cos, const vec2 ofs)
{
cos.xy += ofs * filterSize[cascadeID];
return cos;
}
#else /* CUBEMAP */
/* global vars */
vec3 T = vec3(0.0);
vec3 B = vec3(0.0);
void make_orthonormal_basis(vec3 N)
{
vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
T = normalize(cross(UpVector, N));
B = cross(N, T);
}
vec3 get_texco(vec3 cos, const vec2 ofs)
{
return cos + ofs.x * T + ofs.y * B;
}
#endif
#ifdef ESM
void grouped_samples_accum(vec3 cos,
const vec2 co1,
const vec2 co2,
const vec2 co3,
const vec2 co4,
float ref,
inout vec4 accum)
{
vec4 depths;
depths.x = texture(shadowTexture, get_texco(cos, co1)).r;
depths.y = texture(shadowTexture, get_texco(cos, co2)).r;
depths.z = texture(shadowTexture, get_texco(cos, co3)).r;
depths.w = texture(shadowTexture, get_texco(cos, co4)).r;
accum += ln_space_prefilter_step(ref, depths);
}
#else /* VSM */
void grouped_samples_accum(vec3 cos,
const vec2 co1,
const vec2 co2,
const vec2 co3,
const vec2 co4,
float ref,
inout vec2 accum)
{
vec4 depths1, depths2;
depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg;
depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg;
depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg;
depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg;
accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
}
#endif
void main()
{
vec3 cos;
cos.xy = gl_FragCoord.xy * storedTexelSize;
#ifdef CSM
cos.z = float(cascadeID);
#else /* CUBEMAP */
/* add a 2 pixel border to ensure filtering is correct */
cos.xy *= 1.0 + storedTexelSize * 2.0;
cos.xy -= storedTexelSize;
float pattern = 1.0;
/* edge mirroring : only mirror if directly adjacent
* (not diagonally adjacent) */
vec2 m = abs(cos.xy - 0.5) + 0.5;
vec2 f = floor(m);
if (f.x - f.y != 0.0) {
cos.xy = 1.0 - cos.xy;
}
/* clamp to [0-1] */
cos.xy = fract(cos.xy);
/* get cubemap vector */
cos = normalize(octahedral_to_cubemap_proj(cos.xy));
make_orthonormal_basis(cos);
T *= filterSize[cascadeID];
B *= filterSize[cascadeID];
#endif
#ifdef ESM
/* disc blur in log space. */
vec4 depths;
depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r;
depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r;
depths.z = texture(shadowTexture, get_texco(cos, concentric[2])).r;
depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r;
float ref = depths.x;
vec4 accum = ln_space_prefilter_step(ref, depths);
#else /* VSM */
float ref = 0.0; /* UNUSED */
vec2 accum = vec2(0.0);
grouped_samples_accum(
cos, concentric[0], concentric[1], concentric[2], concentric[3], ref, accum);
#endif
/**
* Making the `grouped_samples_accum` be called within a loop would be
* the most conventional solution, however in some older gpus, transverse the huge
* `const vec2 concentric[]` array with variable indices is extremely slow.
* The solution is to use constant indices to access the array.
*/
if (shadowSampleCount[cascadeID] > 4) {
grouped_samples_accum(
cos, concentric[4], concentric[5], concentric[6], concentric[7], ref, accum);
grouped_samples_accum(
cos, concentric[8], concentric[9], concentric[10], concentric[11], ref, accum);
grouped_samples_accum(
cos, concentric[12], concentric[13], concentric[14], concentric[15], ref, accum);
}
if (shadowSampleCount[cascadeID] > 16) {
grouped_samples_accum(
cos, concentric[16], concentric[17], concentric[18], concentric[19], ref, accum);
grouped_samples_accum(
cos, concentric[20], concentric[21], concentric[22], concentric[23], ref, accum);
grouped_samples_accum(
cos, concentric[24], concentric[25], concentric[26], concentric[27], ref, accum);
grouped_samples_accum(
cos, concentric[28], concentric[29], concentric[30], concentric[31], ref, accum);
grouped_samples_accum(
cos, concentric[32], concentric[33], concentric[34], concentric[35], ref, accum);
}
#ifdef HIGH_BLUR
if (shadowSampleCount[cascadeID] > 36) {
grouped_samples_accum(
cos, concentric[36], concentric[37], concentric[38], concentric[39], ref, accum);
grouped_samples_accum(
cos, concentric[40], concentric[41], concentric[42], concentric[43], ref, accum);
grouped_samples_accum(
cos, concentric[44], concentric[45], concentric[46], concentric[47], ref, accum);
grouped_samples_accum(
cos, concentric[48], concentric[49], concentric[50], concentric[51], ref, accum);
grouped_samples_accum(
cos, concentric[52], concentric[53], concentric[54], concentric[55], ref, accum);
grouped_samples_accum(
cos, concentric[56], concentric[57], concentric[58], concentric[59], ref, accum);
grouped_samples_accum(
cos, concentric[60], concentric[61], concentric[62], concentric[63], ref, accum);
}
if (shadowSampleCount[cascadeID] > 64) {
grouped_samples_accum(
cos, concentric[64], concentric[65], concentric[66], concentric[67], ref, accum);
grouped_samples_accum(
cos, concentric[68], concentric[69], concentric[70], concentric[71], ref, accum);
grouped_samples_accum(
cos, concentric[72], concentric[73], concentric[74], concentric[75], ref, accum);
grouped_samples_accum(
cos, concentric[76], concentric[77], concentric[78], concentric[79], ref, accum);
grouped_samples_accum(
cos, concentric[80], concentric[81], concentric[82], concentric[83], ref, accum);
grouped_samples_accum(
cos, concentric[84], concentric[85], concentric[86], concentric[87], ref, accum);
grouped_samples_accum(
cos, concentric[88], concentric[89], concentric[90], concentric[91], ref, accum);
grouped_samples_accum(
cos, concentric[92], concentric[93], concentric[94], concentric[95], ref, accum);
grouped_samples_accum(
cos, concentric[96], concentric[97], concentric[98], concentric[99], ref, accum);
}
if (shadowSampleCount[cascadeID] > 100) {
grouped_samples_accum(
cos, concentric[100], concentric[101], concentric[102], concentric[103], ref, accum);
grouped_samples_accum(
cos, concentric[104], concentric[105], concentric[106], concentric[107], ref, accum);
grouped_samples_accum(
cos, concentric[108], concentric[109], concentric[110], concentric[111], ref, accum);
grouped_samples_accum(
cos, concentric[112], concentric[113], concentric[114], concentric[115], ref, accum);
grouped_samples_accum(
cos, concentric[116], concentric[117], concentric[118], concentric[119], ref, accum);
grouped_samples_accum(
cos, concentric[120], concentric[121], concentric[122], concentric[123], ref, accum);
grouped_samples_accum(
cos, concentric[124], concentric[125], concentric[126], concentric[127], ref, accum);
grouped_samples_accum(
cos, concentric[128], concentric[129], concentric[130], concentric[131], ref, accum);
grouped_samples_accum(
cos, concentric[132], concentric[133], concentric[134], concentric[135], ref, accum);
grouped_samples_accum(
cos, concentric[136], concentric[137], concentric[138], concentric[139], ref, accum);
grouped_samples_accum(
cos, concentric[140], concentric[141], concentric[142], concentric[143], ref, accum);
}
if (shadowSampleCount[cascadeID] > 144) {
grouped_samples_accum(
cos, concentric[144], concentric[145], concentric[146], concentric[147], ref, accum);
grouped_samples_accum(
cos, concentric[148], concentric[149], concentric[150], concentric[151], ref, accum);
grouped_samples_accum(
cos, concentric[152], concentric[153], concentric[154], concentric[155], ref, accum);
grouped_samples_accum(
cos, concentric[156], concentric[157], concentric[158], concentric[159], ref, accum);
grouped_samples_accum(
cos, concentric[160], concentric[161], concentric[162], concentric[163], ref, accum);
grouped_samples_accum(
cos, concentric[164], concentric[165], concentric[166], concentric[167], ref, accum);
grouped_samples_accum(
cos, concentric[168], concentric[169], concentric[170], concentric[171], ref, accum);
grouped_samples_accum(
cos, concentric[172], concentric[173], concentric[174], concentric[175], ref, accum);
grouped_samples_accum(
cos, concentric[176], concentric[177], concentric[178], concentric[179], ref, accum);
grouped_samples_accum(
cos, concentric[180], concentric[181], concentric[182], concentric[183], ref, accum);
grouped_samples_accum(
cos, concentric[184], concentric[185], concentric[186], concentric[187], ref, accum);
grouped_samples_accum(
cos, concentric[188], concentric[189], concentric[190], concentric[191], ref, accum);
grouped_samples_accum(
cos, concentric[192], concentric[193], concentric[194], concentric[195], ref, accum);
}
if (shadowSampleCount[cascadeID] > 196) {
grouped_samples_accum(
cos, concentric[196], concentric[197], concentric[198], concentric[199], ref, accum);
grouped_samples_accum(
cos, concentric[200], concentric[201], concentric[202], concentric[203], ref, accum);
grouped_samples_accum(
cos, concentric[204], concentric[205], concentric[206], concentric[207], ref, accum);
grouped_samples_accum(
cos, concentric[208], concentric[209], concentric[210], concentric[211], ref, accum);
grouped_samples_accum(
cos, concentric[212], concentric[213], concentric[114], concentric[215], ref, accum);
grouped_samples_accum(
cos, concentric[216], concentric[217], concentric[218], concentric[219], ref, accum);
grouped_samples_accum(
cos, concentric[220], concentric[221], concentric[222], concentric[223], ref, accum);
grouped_samples_accum(
cos, concentric[224], concentric[225], concentric[226], concentric[227], ref, accum);
grouped_samples_accum(
cos, concentric[228], concentric[229], concentric[230], concentric[231], ref, accum);
grouped_samples_accum(
cos, concentric[232], concentric[233], concentric[234], concentric[235], ref, accum);
grouped_samples_accum(
cos, concentric[236], concentric[237], concentric[238], concentric[239], ref, accum);
grouped_samples_accum(
cos, concentric[240], concentric[241], concentric[242], concentric[243], ref, accum);
grouped_samples_accum(
cos, concentric[244], concentric[245], concentric[246], concentric[247], ref, accum);
grouped_samples_accum(
cos, concentric[248], concentric[249], concentric[250], concentric[251], ref, accum);
grouped_samples_accum(
cos, concentric[252], concentric[253], concentric[254], concentric[255], ref, accum);
}
#endif
#ifdef ESM
accum.x = dot(vec4(1.0), accum);
accum.x = ln_space_prefilter_finalize(ref, accum.x);
FragColor = accum.xxxx;
#else /* VSM */
FragColor = accum.xyxy * shadowInvSampleCount[cascadeID];
#endif
}

View File

@ -346,6 +346,7 @@ typedef enum {
/** Use dual source blending. WARNING: Only one color buffer allowed. */
DRW_STATE_BLEND_CUSTOM = (1 << 23),
DRW_STATE_SHADOW_OFFSET = (1 << 27),
DRW_STATE_CLIP_PLANES = (1 << 28),
DRW_STATE_WIRE_SMOOTH = (1 << 29),
DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30),

View File

@ -279,6 +279,23 @@ void drw_state_set(DRWState state)
}
}
/* Shadow Bias */
{
int test;
if ((test = CHANGED_TO(DRW_STATE_SHADOW_OFFSET))) {
if (test == 1) {
glEnable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_POLYGON_OFFSET_LINE);
/* 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);
glDisable(GL_POLYGON_OFFSET_LINE);
}
}
}
/* Clip Planes */
{
int test;

View File

@ -46,8 +46,9 @@ typedef enum {
GPU_FB_COLOR_ATTACHMENT2,
GPU_FB_COLOR_ATTACHMENT3,
GPU_FB_COLOR_ATTACHMENT4,
GPU_FB_COLOR_ATTACHMENT5,
/* Number of maximum output slots.
* We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */
* We support 6 outputs for now (usually we wouldn't need more to preserve fill rate). */
/* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to
* the maximum number of COLOR attachments specified by glDrawBuffers. */
GPU_FB_MAX_ATTACHEMENT,
@ -82,6 +83,7 @@ static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
[GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2,
[GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3,
[GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4,
[GPU_FB_COLOR_ATTACHMENT5] = GL_COLOR_ATTACHMENT5,
};
return table[type];
}

View File

@ -3,7 +3,7 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
{
N = normalize(N);
result = CLOSURE_DEFAULT;
eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance);
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
result.radiance *= color.rgb;
}

View File

@ -25,6 +25,7 @@ void node_eevee_specular(vec4 diffuse,
clearcoat * 0.25,
clearcoat_roughness,
occlusion,
true,
out_diff,
out_spec,
ssr_spec);

View File

@ -6,8 +6,17 @@ void node_bsdf_glass(
vec3 out_spec, out_refr, ssr_spec;
vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb :
color.rgb; /* Simulate 2 transmission event */
eevee_closure_glass(
N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
eevee_closure_glass(N,
vec3(1.0),
vec3(1.0),
int(ssr_id),
roughness,
1.0,
ior,
true,
out_spec,
out_refr,
ssr_spec);
out_refr *= refr_color;
out_spec *= color.rgb;
float fresnel = F_eta(ior, dot(N, cameraVec));

View File

@ -3,7 +3,8 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo
{
N = normalize(N);
vec3 out_spec, ssr_spec;
eevee_closure_glossy(N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
eevee_closure_glossy(
N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.radiance = out_spec * color.rgb;

View File

@ -66,7 +66,7 @@ void node_bsdf_principled(vec4 base_color,
sheen *= dielectric;
subsurface_color *= dielectric;
vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec;
vec3 ctint = tint_from_color(base_color.rgb);
convert_metallic_to_specular_tinted(
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
@ -99,8 +99,8 @@ void node_bsdf_principled(vec4 base_color,
1.0,
sss_scalef,
ior,
true,
out_diff,
out_trans,
out_spec,
out_refr,
ssr_spec);
@ -116,24 +116,8 @@ void node_bsdf_principled(vec4 base_color,
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
vec3 sss_radiance = (out_diff + out_trans) * alpha;
# ifndef USE_SSS
result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
# else
# ifdef USE_SSS_ALBEDO
vec3 sss_albedo = mixed_ss_base_color;
# else
sss_radiance *= mixed_ss_base_color;
# endif
sss_radiance *= (1.0 - transmission);
closure_load_sss_data(sss_scalef,
sss_radiance,
# ifdef USE_SSS_ALBEDO
sss_albedo,
# endif
int(sss_id),
result);
# endif /* USE_SSS */
mixed_ss_base_color *= alpha * (1.0 - transmission);
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
result.radiance += emission.rgb;
result.radiance *= alpha;
@ -181,7 +165,7 @@ void node_bsdf_principled_dielectric(vec4 base_color,
vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
eevee_closure_default(
N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
N, diffuse, f0, vec3(1.0), int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec);
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * (diffuse + out_sheen);
@ -224,7 +208,8 @@ void node_bsdf_principled_metallic(vec4 base_color,
vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic);
eevee_closure_glossy(N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
eevee_closure_glossy(
N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec);
result = CLOSURE_DEFAULT;
result.radiance = out_spec;
@ -276,6 +261,7 @@ void node_bsdf_principled_clearcoat(vec4 base_color,
clearcoat * 0.25,
clearcoat_roughness,
1.0,
true,
out_spec,
ssr_spec);
@ -318,7 +304,7 @@ void node_bsdf_principled_subsurface(vec4 base_color,
metallic = saturate(metallic);
N = normalize(N);
vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
vec3 ctint = tint_from_color(base_color.rgb);
convert_metallic_to_specular_tinted(
base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
@ -340,8 +326,8 @@ void node_bsdf_principled_subsurface(vec4 base_color,
roughness,
1.0,
sss_scalef,
true,
out_diff,
out_trans,
out_spec,
ssr_spec);
@ -349,24 +335,8 @@ void node_bsdf_principled_subsurface(vec4 base_color,
result.radiance = out_spec;
closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result);
vec3 sss_radiance = (out_diff + out_trans) * alpha;
# ifndef USE_SSS
result.radiance += sss_radiance * mixed_ss_base_color * (1.0 - transmission);
# else
# ifdef USE_SSS_ALBEDO
vec3 sss_albedo = mixed_ss_base_color;
# else
sss_radiance *= mixed_ss_base_color;
# endif
sss_radiance *= (1.0 - transmission);
closure_load_sss_data(sss_scalef,
sss_radiance,
# ifdef USE_SSS_ALBEDO
sss_albedo,
# endif
int(sss_id),
result);
# endif /* USE_SSS */
mixed_ss_base_color *= alpha * (1.0 - transmission);
closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result);
result.radiance += out_diff * out_sheen;
result.radiance += emission.rgb;
@ -408,8 +378,17 @@ void node_bsdf_principled_glass(vec4 base_color,
vec3 f0, out_spec, out_refr, ssr_spec;
f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
eevee_closure_glass(
N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
eevee_closure_glass(N,
vec3(1.0),
vec3(1.0),
int(ssr_id),
roughness,
1.0,
ior,
true,
out_spec,
out_refr,
ssr_spec);
vec3 refr_color = base_color.rgb;
refr_color *= (refractionDepth > 0.0) ? refr_color :

View File

@ -4,7 +4,7 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl
N = normalize(N);
vec3 out_refr;
color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
eevee_closure_refraction(N, roughness, ior, out_refr);
eevee_closure_refraction(N, roughness, ior, true, out_refr);
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
result.ssr_normal = normal_encode(vN, viewCameraVec);

View File

@ -15,11 +15,7 @@ void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
# ifdef USE_SSS
# ifdef USE_SSS_ALBEDO
outcol.rgb += cl.sss_data.rgb * cl.sss_albedo;
# else
outcol.rgb += cl.sss_data.rgb;
# endif
outcol.rgb += cl.sss_irradiance.rgb * cl.sss_albedo;
# endif
}
#endif /* VOLUMETRICS */

View File

@ -8,33 +8,18 @@ void node_subsurface_scattering(vec4 color,
float sss_id,
out Closure result)
{
# if defined(USE_SSS)
N = normalize(N);
vec3 out_diff, out_trans;
vec3 out_diff;
vec3 vN = mat3(ViewMatrix) * N;
result = CLOSURE_DEFAULT;
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff);
vec3 sss_radiance = out_diff + out_trans;
# ifdef USE_SSS_ALBEDO
/* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur);
sss_radiance *= mix(vec3(1.0), color.rgb, texture_blur);
# else
sss_radiance *= color.rgb;
# endif
closure_load_sss_data(scale,
sss_radiance,
# ifdef USE_SSS_ALBEDO
sss_albedo,
# endif
int(sss_id),
result);
# else
node_bsdf_diffuse(color, 0.0, N, result);
# endif
out_diff *= mix(vec3(1.0), color.rgb, texture_blur);
closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result);
}
#else
/* Stub subsurface scattering because it is not compatible with volumetrics. */

View File

@ -1,7 +1,11 @@
#ifndef VOLUMETRICS
void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
{
node_bsdf_diffuse(color, 0.0, -N, result);
N = normalize(N);
result = CLOSURE_DEFAULT;
eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance);
closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result);
result.radiance *= color.rgb;
}
#else
/* Stub translucent because it is not compatible with volumetrics. */

View File

@ -58,7 +58,10 @@ typedef struct Light {
char _pad2[2];
float clipsta, clipend;
float bias, soft, bleedbias, bleedexp;
float bias;
float soft; /* DEPRECATED kept for compatibility. */
float bleedbias; /* DEPRECATED kept for compatibility. */
float bleedexp; /* DEPRECATED kept for compatibility. */
short bufsize, samp, buffers, filtertype;
char bufflag, buftype;
@ -82,7 +85,10 @@ typedef struct Light {
float cascade_fade;
int cascade_count;
float contact_dist, contact_bias, contact_spread, contact_thickness;
float contact_dist;
float contact_bias;
float contact_spread; /* DEPRECATED kept for compatibility. */
float contact_thickness;
float spec_fac, att_dist;

View File

@ -1637,7 +1637,7 @@ typedef struct SceneEEVEE {
int motion_blur_samples;
float motion_blur_shutter;
int shadow_method;
int shadow_method DNA_DEPRECATED;
int shadow_cube_size;
int shadow_cascade_size;
@ -2392,7 +2392,7 @@ enum {
SCE_EEVEE_SHADOW_HIGH_BITDEPTH = (1 << 10),
SCE_EEVEE_TAA_REPROJECTION = (1 << 11),
// SCE_EEVEE_SSS_ENABLED = (1 << 12), /* Unused */
SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13),
// SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13), /* Unused */
SCE_EEVEE_SSR_ENABLED = (1 << 14),
SCE_EEVEE_SSR_REFRACTION = (1 << 15),
SCE_EEVEE_SSR_HALF_RESOLUTION = (1 << 16),

View File

@ -297,16 +297,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
"Shadow map clip start, below which objects will not generate shadows");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
RNA_def_property_float_default(prop, 40.0f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop,
"Shadow Buffer Clip End",
"Shadow map clip end, beyond which objects will not generate shadows");
RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bias");
RNA_def_property_float_default(prop, 1.0f);
@ -315,28 +305,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Bias for reducing self shadowing");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_bleed_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bleedbias");
RNA_def_property_range(prop, 0.f, 1.f);
RNA_def_property_ui_text(
prop, "Shadow Buffer Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_exp", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bleedexp");
RNA_def_property_float_default(prop, 2.5f);
RNA_def_property_range(prop, 1.0f, 9999.0f);
RNA_def_property_ui_text(
prop, "Shadow Buffer Exponent", "Bias for reducing light-bleed on exponential shadow maps");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_soft", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "soft");
RNA_def_property_float_default(prop, 3.0f);
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_text(prop, "Shadow Buffer Soft", "Size of shadow buffer sampling area");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samp");
RNA_def_property_range(prop, 1, 16);
@ -386,14 +354,6 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
RNA_def_property_ui_text(prop, "Contact Shadow Bias", "Bias to avoid self shadowing");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "contact_shadow_soft_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "contact_spread");
RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(
prop, "Contact Shadow Soft", "Control how soft the contact shadows will be");
RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "contact_shadow_thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "contact_thickness");
RNA_def_property_float_default(prop, 0.2f);

View File

@ -6662,12 +6662,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem eevee_shadow_method_items[] = {
{SHADOW_ESM, "ESM", 0, "ESM", "Exponential Shadow Mapping"},
{SHADOW_VSM, "VSM", 0, "VSM", "Variance Shadow Mapping"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem eevee_shadow_size_items[] = {
{64, "64", 0, "64px", ""},
{128, "128", 0, "128px", ""},
@ -6837,16 +6831,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_sss_separate_albedo", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_SEPARATE_ALBEDO);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop,
"Separate Albedo",
"Avoid albedo being blurred by the subsurface scattering "
"but uses more video memory");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
/* Screen Space Reflection */
prop = RNA_def_property(srna, "use_ssr", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_ENABLED);
@ -7127,13 +7111,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
/* Shadows */
prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_default(prop, SHADOW_ESM);
RNA_def_property_enum_items(prop, eevee_shadow_method_items);
RNA_def_property_ui_text(prop, "Method", "Technique use to compute the shadows");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_default(prop, 512);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);