Eevee: Shadow map refactor
Reviewed By: brecht Differential Revision: http://developer.blender.org/D5659
This commit is contained in:
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
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
/* ---------------------------- */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ void node_eevee_specular(vec4 diffuse,
|
|||
clearcoat * 0.25,
|
||||
clearcoat_roughness,
|
||||
occlusion,
|
||||
true,
|
||||
out_diff,
|
||||
out_spec,
|
||||
ssr_spec);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 :
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue