1
1

Compare commits

...

24 Commits

Author SHA1 Message Date
b063115d4e EEVEE: Remove softness parameters from RNA & UI
Keep it in DNA for backward compatibility
2019-09-02 16:41:07 +02:00
312dbf8af1 EEVEE: Fix sunlight when sun angle is 180 degrees 2019-09-02 16:41:07 +02:00
eb8093cb14 EEVEE: Shadow: Add back shadow bias
This is needed in some corner case (shadow acne due to aliasing and depth
disparity). This is a simple bias added to default bias. It should not be
needed most of the time but we leave it at 1 by default.
2019-09-02 16:41:07 +02:00
6adaa4202a EEVEE: Fix spotlight shadow optimization
Spot light can be non-uniform and scale in one direction. This fix makes
sure both directions are taken into account before skipping cubemap faces.
2019-09-02 16:41:07 +02:00
4dd3a9790f UI: Make cascaded shadowmap panel on top of contact shadow
This make more sense as cascade parameters are more important.
2019-09-02 16:41:07 +02:00
c584116e25 EEVEE: Shadow: Add temporal sampling to shadowmaps
If soft shadows is enabled, we randomize the shadowmap sample position
to reduce aliasing artifacts (jagged edge shadows).
2019-09-02 16:41:07 +02:00
3e10785c60 Cleanup: EEVEE: Split eevee_lights.c into smaller files
Also have some const correctness fix and some header cleanup.
2019-09-02 16:41:07 +02:00
9468425524 Eevee: Shadow: Refactor / Cleanup of shadow update
- Replace EEVEE_lightbits by BLI_bitmap
- Replace EEVEE_BoundSphere by BoundSphere
- Support for dupli light shadows
- Detect unecessary update of soft shadows (i.e: moving the view)
- Remove Object references
2019-09-02 16:41:07 +02:00
31e21d38e3 Eevee: Light: Refactor shadow tagging to allow dupli shadow casters
Dupli objects can now cast shadows.

This also replace the custom lightbits by BLI_bitmap.
2019-09-02 16:41:07 +02:00
8457593672 Eevee: Shadows: Add texel border on shadow cube for better edge filtering
Unfortunately, this seems to be imprecise on lower cube resolution. But
the result is still most of the time more pleasant than no border filtering.
2019-09-02 16:41:06 +02:00
e13f5cc5ae Eevee: Shadow: Speedup: Only render shadow cube face needed
This reduce the number of face to render to 5 in the case of area lights
and 5 or 1 for spotlights.

Spotlights that have a spot size less than 90 degrees only need 1 face and
are the fastest.
2019-09-02 16:41:06 +02:00
278d174e35 Eevee: Shadows: Make shadowmap follow light orientation
This is in preparation of an optimization
2019-09-02 16:41:06 +02:00
d5555e5d5a DRW: Add line offset to DRW_STATE_SHADOW_OFFSET
This is needed for hairs.
2019-09-02 16:41:06 +02:00
585eaa5b0a Eevee: Shadows: Improve contact shadows
Contact shadows now follow the shadowmap direction. This means it matches
the shadowmap blur that is proportional to the light radius.

Moreover this adds a more efficient bias for most contact shadows.
2019-09-02 16:41:06 +02:00
4ec63b5421 Eevee: Shadow: Speedup: Use only 2 sample for cascaded shadowmap 2019-09-02 16:41:06 +02:00
a77301289d Eevee: Shadow: Remove receiver plane bias and use hardware filtering
In an attempt to simplify the shadowing in eevee, we remove the bias and
filtering option.

Now the shadowmap always get the minimum constant and slope bias and we
only do a bilinear shadow filtering. This means the shadow is as sharper
and exact as the shadow map format allows (bitdepth and size).

Only the lamp size can change the shadow softness.
2019-09-02 16:41:06 +02:00
95a3c256dc Eevee: Shadow: Make sun clip distances automatic
This simplify sun lights setup and matches more cycles behavior.
2019-09-02 16:41:06 +02:00
0edd48c904 Eevee: Remove ESM and VSM code 2019-09-02 16:41:06 +02:00
9e19ec0d18 Eevee: Shadows: Add Receiver Plane Depth Bias
This bias replace the previous bias method. The bias is now scalled to
have the correct depth of the triangle at the sample location. This is done
by computing the actual depth that would be recorded in the shadowmap
at the texels locations, if the triangle was extrapolated.

This leads to less shadow acne and it ensure the bias is always the minimum
amount that ensure correct shadowing.

However this technique is not failure free and if the receiver is nearly
parallel to the light, the bias is nearly infinite and light leaking occurs.

For this reason I decided to cap the bias by the bias parameter to tweak
between shadow acne and light leaking.
2019-09-02 16:41:06 +02:00
e951f5f0fe Eevee: Replace ESM and VSM by PCF shadow mapping
PCF shadowmaps are less prone to light leaking and are faster to
render.

This remove a substantial part of the shadowing code.
2019-09-02 16:41:06 +02:00
4df76629a5 DRW: Add shadow bias state
This state add shadowmap bias to avoid most of self shadowing.
2019-09-02 16:41:06 +02:00
786b0c6414 Eevee: SSS: Refactor translucency
This separate the translucency evaluation to be outside of surface eval.

This as the benefit to reduce code complexity and remove the need for
shadow map (non-test) sampler in the shading pass.

One big change is that bsdf intensity is multiplied and stored with the
albedo color instead of the sss irradiance. This is in order to apply it
to both the translucency and the sss diffusion. This change the look of
mixed SSS shaders which is now closer to cycles.

Performance cost is negligeable.

# Conflicts:
#	source/blender/gpu/shaders/gpu_shader_material.glsl
2019-09-02 16:41:02 +02:00
9ee5e73a3d Eevee: SSS: Refactor to use less memory and always use separate albedo
This refactor reduce the Memory overhead of SSS and enables us to always
use separate albedo. Previously we used 128bits/px for SSS data and
32bits/px for albedo. Now we use 112bits/px for SSS data & separate albedo
altogether.

This refactor is needed for PCF shadow maps.

# Conflicts:
#	source/blender/gpu/shaders/gpu_shader_material.glsl
2019-09-02 16:38:14 +02:00
77a0ef91ba GPUFramebuffer: Bump max color attachement to 6 2019-09-02 16:30:48 +02:00
39 changed files with 1928 additions and 2839 deletions

View File

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

View File

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

View File

@@ -958,7 +958,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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -63,8 +63,6 @@ static struct {
struct GPUTexture *util_tex;
struct GPUTexture *noise_tex;
struct GPUUniformBuffer *dummy_sss_profile;
uint sss_count;
float alpha_hash_offset;
@@ -273,21 +271,6 @@ struct GPUTexture *EEVEE_materials_get_util_tex(void)
return e_data.util_tex;
}
static int eevee_material_shadow_option(int shadow_method)
{
switch (shadow_method) {
case SHADOW_ESM:
return VAR_MAT_ESM;
case SHADOW_VSM:
return VAR_MAT_VSM;
default:
BLI_assert(!"Incorrect Shadow Method");
break;
}
return 0;
}
static char *eevee_get_defines(int options)
{
char *str = NULL;
@@ -322,23 +305,11 @@ 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 +406,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 +597,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,23 +696,18 @@ 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_translucency)
{
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) {
return mat;
@@ -835,13 +795,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 +830,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 +839,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 +858,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 +870,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 +1116,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 +1137,9 @@ 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, use_translucency) :
NULL;
*gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
NULL;
@@ -1203,8 +1152,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, use_translucency);
eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
@@ -1311,15 +1259,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 +1275,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 +1295,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 +1335,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 +1350,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, false);
switch (GPU_material_status(*gpumat)) {
case GPU_MAT_SUCCESS: {
@@ -1461,7 +1393,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 +1582,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 +1660,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 +1705,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 +1749,25 @@ 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 *sldata, EEVEE_PassList *psl)
{
/* We sample the shadowmaps using shadow sampler. We need to enable Comparison mode.
* TODO(fclem) avoid this by using sampler objects.*/
GPU_texture_bind(sldata->shadow_cube_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
GPU_texture_unbind(sldata->shadow_cube_pool);
GPU_texture_bind(sldata->shadow_cascade_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
GPU_texture_unbind(sldata->shadow_cascade_pool);
for (int i = 0; i < VAR_MAT_MAX; ++i) {
if (psl->default_pass[i]) {
DRW_draw_pass(psl->default_pass[i]);
}
}
DRW_draw_pass(psl->material_pass);
DRW_draw_pass(psl->material_pass_cull);
}

View File

@@ -23,9 +23,12 @@
#ifndef __EEVEE_PRIVATE_H__
#define __EEVEE_PRIVATE_H__
#include "DRW_render.h"
#include "BLI_bitmap.h"
#include "DNA_lightprobe_types.h"
struct EEVEE_BoundSphere;
struct EEVEE_ShadowCasterBuffer;
struct GPUFrameBuffer;
struct Object;
@@ -39,11 +42,13 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */
#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
#define MAX_CASCADE_NUM 4
#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW 128 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
#define MAX_SHADOW_CASCADE 8
#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
#define MAX_BLOOM_STEP 16
// #define DEBUG_SHADOW_DISTRIBUTION
/* Only define one of these. */
// #define IRRADIANCE_SH_L2
// #define IRRADIANCE_CUBEMAP
@@ -147,14 +152,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),
@@ -163,7 +166,6 @@ enum {
VAR_MAT_SHADOW = (1 << 12),
VAR_MAT_REFRACT = (1 << 13),
VAR_MAT_TRANSLUC = (1 << 15),
VAR_MAT_SSSALBED = (1 << 16),
};
/* ************ PROBE UBO ************* */
@@ -187,10 +189,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;
@@ -198,12 +196,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;
@@ -239,6 +231,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;
@@ -289,6 +282,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;
@@ -365,7 +359,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;
@@ -375,13 +369,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 {
@@ -389,42 +383,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;
@@ -434,42 +420,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 */
@@ -549,8 +524,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;
@@ -708,20 +683,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;
@@ -743,23 +708,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. */
@@ -767,13 +715,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 {
@@ -897,38 +838,66 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
EEVEE_Data *vedata,
bool use_blend,
bool use_refract,
bool use_translucency,
int shadow_method);
bool use_translucency);
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);
@@ -1041,6 +1010,11 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile);
void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint sss_id,
struct GPUUniformBuffer *sss_profile,
struct GPUTexture *sss_tex_profile);
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -595,7 +595,7 @@ void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
effects->volume_transmit = e_data.dummy_transmit;
}
void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
@@ -605,6 +605,15 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
DRW_stats_group_start("Volumetrics");
/* We sample the shadowmaps using shadow sampler. We need to enable Comparison mode.
* TODO(fclem) avoid this by using sampler objects.*/
GPU_texture_bind(sldata->shadow_cube_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
GPU_texture_unbind(sldata->shadow_cube_pool);
GPU_texture_bind(sldata->shadow_cascade_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
GPU_texture_unbind(sldata->shadow_cascade_pool);
GPU_framebuffer_bind(fbl->volumetric_fb);
DRW_draw_pass(psl->volumetric_world_ps);
DRW_draw_pass(psl->volumetric_objects_ps);

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
uniform sampler2DArray shadowCubeTexture;
uniform sampler2DArray shadowCascadeTexture;
uniform sampler2DArrayShadow shadowCubeTexture;
uniform sampler2DArrayShadow shadowCascadeTexture;
#define LAMPS_LIB
@@ -24,129 +24,115 @@ layout(std140) uniform light_block
/* Used to define the area light shape, doesn't directly correspond to a Blender light type. */
#define AREA_ELLIPSE 100.0
#if defined(SHADOW_VSM)
# define ShadowSample vec2
# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg
# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg
#elif defined(SHADOW_ESM)
# define ShadowSample float
# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
#else
# define ShadowSample float
# define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
# define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
#endif
#if defined(SHADOW_VSM)
# define get_depth_delta(dist, s) (dist - s.x)
#else
# define get_depth_delta(dist, s) (dist - s)
#endif
/* ----------------------------------------------------------- */
/* ----------------------- Shadow tests ---------------------- */
/* ----------------------------------------------------------- */
#if defined(SHADOW_VSM)
float shadow_test(ShadowSample moments, float dist, ShadowData sd)
float cubeFaceIndexEEVEE(vec3 P)
{
float p = 0.0;
if (dist <= moments.x) {
p = 1.0;
vec3 aP = abs(P);
if (all(greaterThan(aP.xx, aP.yz))) {
return (P.x > 0.0) ? 0.0 : 1.0;
}
float variance = moments.y - (moments.x * moments.x);
variance = max(variance, sd.sh_bias / 10.0);
float d = moments.x - dist;
float p_max = variance / (variance + d * d);
/* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
p_max = clamp((p_max - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0);
return max(p, p_max);
}
#elif defined(SHADOW_ESM)
float shadow_test(ShadowSample z, float dist, ShadowData sd)
{
return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias)));
}
#else
float shadow_test(ShadowSample z, float dist, ShadowData sd)
{
return step(0, z - dist + sd.sh_bias);
}
#endif
/* ----------------------------------------------------------- */
/* ----------------------- Shadow types ---------------------- */
/* ----------------------------------------------------------- */
float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
{
vec3 cubevec = W - scd.position.xyz;
float dist = length(cubevec);
cubevec /= dist;
ShadowSample s = sample_cube(cubevec, texid);
return shadow_test(s, dist, sd);
}
float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid)
{
vec4 shpos = shadowmat * vec4(W, 1.0);
float dist = shpos.z * range;
ShadowSample s = sample_cascade(shpos.xy, texid);
float vis = shadow_test(s, dist, sd);
/* If fragment is out of shadowmap range, do not occlude */
if (shpos.z < 1.0 && shpos.z > 0.0) {
return vis;
else if (all(greaterThan(aP.yy, aP.xz))) {
return (P.y > 0.0) ? 2.0 : 3.0;
}
else {
return 1.0;
return (P.z > 0.0) ? 4.0 : 5.0;
}
}
float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W)
vec2 cubeFaceCoordEEVEE(vec3 P, float face, float scale)
{
if (face < 2.0) {
return (P.zy / P.x) * scale * vec2(-0.5, -sign(P.x) * 0.5) + 0.5;
}
else if (face < 4.0) {
return (P.xz / P.y) * scale * vec2(sign(P.y) * 0.5, 0.5) + 0.5;
}
else {
return (P.xy / P.z) * scale * vec2(0.5, -sign(P.z) * 0.5) + 0.5;
}
}
vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArray tex)
{
/* Scaling to compensate the 1px border around the face. */
float cube_res = float(textureSize(tex, 0).x);
float scale = (cube_res) / (cube_res + 1.0);
return cubeFaceCoordEEVEE(P, face, scale);
}
vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex)
{
/* Scaling to compensate the 1px border around the face. */
float cube_res = float(textureSize(tex, 0).x);
float scale = (cube_res) / (cube_res + 1.0);
return cubeFaceCoordEEVEE(P, face, scale);
}
vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube)
{
/* Manual Shadow Cube Layer indexing. */
/* TODO Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex);
vec3 coord = vec3(uv, cube * 6.0 + face);
return texture(tex, coord);
}
vec4 sample_cascade(sampler2DArray tex, vec2 co, float cascade_id)
{
return texture(tex, vec3(co, cascade_id));
}
/* Some driver poorly optimize this code. Use direct reference to matrices. */
#define sd(x) shadows_data[x]
#define scube(x) shadows_cube_data[x]
#define scascade(x) shadows_cascade_data[x]
float sample_cube_shadow(int shadow_id, vec3 W)
{
int data_id = int(sd(shadow_id).sh_data_index);
vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
float dist = max_v3(abs(cubevec)) - sd(shadow_id).sh_bias;
dist = buffer_depth(true, dist, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
/* Manual Shadow Cube Layer indexing. */
/* TODO Shadow Cube Array. */
float face = cubeFaceIndexEEVEE(cubevec);
vec2 coord = cubeFaceCoordEEVEE(cubevec, face, shadowCubeTexture);
/* tex_id == data_id for cube shadowmap */
float tex_id = float(data_id);
return texture(shadowCubeTexture, vec4(coord, tex_id * 6.0 + face, dist));
}
float sample_cascade_shadow(int shadow_id, vec3 W)
{
int data_id = int(sd(shadow_id).sh_data_index);
float tex_id = scascade(data_id).sh_tex_index;
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
vec4 weights = smoothstep(shadows_cascade_data[scd_id].split_end_distances,
shadows_cascade_data[scd_id].split_start_distances.yzwx,
view_z);
vec4 weights = 1.0 - smoothstep(scascade(data_id).split_end_distances,
scascade(data_id).split_start_distances.yzwx,
view_z);
float tot_weight = dot(weights.xyz, vec3(1.0));
weights.yzw -= weights.xyz;
int cascade = int(clamp(tot_weight, 0.0, 3.0));
float blend = fract(tot_weight);
float vis = weights.w;
vec4 coord, shpos;
/* Main cascade. */
shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
vis += texture(shadowCascadeTexture, coord) * (1.0 - blend);
vec4 vis = vec4(1.0);
float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */
cascade = min(3, cascade + 1);
/* Second cascade. */
shpos = scascade(data_id).shadowmat[cascade] * vec4(W, 1.0);
coord = vec4(shpos.xy, tex_id + float(cascade), shpos.z - sd(shadow_id).sh_bias);
vis += texture(shadowCascadeTexture, coord) * blend;
/* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */
/* TODO OPTI: Only do 2 samples and blend. */
vis.x = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[0], W, range, texid + 0);
vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1);
vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2);
vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3);
float weight_sum = dot(vec4(1.0), weights);
if (weight_sum > 0.9999) {
float vis_sum = dot(vec4(1.0), vis * weights);
return vis_sum / weight_sum;
}
else {
float vis_sum = dot(vec4(1.0), vis * step(0.001, weights));
return mix(1.0, vis_sum, weight_sum);
}
return saturate(vis);
}
#undef sd
#undef scube
#undef scsmd
/* ----------------------------------------------------------- */
/* --------------------- Light Functions --------------------- */
@@ -173,16 +159,9 @@ float spot_attenuation(LightData ld, vec3 l_vector)
return spotmask;
}
float light_visibility(LightData ld,
vec3 W,
#ifndef VOLUMETRICS
vec3 viewPosition,
vec3 vN,
#endif
vec4 l_vector)
float light_attenuation(LightData ld, vec4 l_vector)
{
float vis = 1.0;
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
@@ -192,69 +171,65 @@ 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,
#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 (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 +300,3 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
}
}
#endif
#define MAX_SSS_SAMPLES 65
#define SSS_LUT_SIZE 64.0
#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
#ifdef USE_TRANSLUCENCY
layout(std140) uniform sssProfile
{
vec4 kernel[MAX_SSS_SAMPLES];
vec4 radii_max_radius;
int sss_samples;
};
uniform sampler1D sssTexProfile;
vec3 sss_profile(float s)
{
s /= radii_max_radius.w;
return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
}
#endif
vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
{
#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
return vec3(0.0);
#else
vec3 vis = vec3(1.0);
if (ld.l_type == SPOT) {
vis *= spot_attenuation(ld, l_vector.xyz);
}
if (ld.l_type >= SPOT) {
vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
}
if (ld.l_type != SUN) {
vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
}
/* Only shadowed light can produce translucency */
if (ld.l_shadowid >= 0.0 && vis.x > 0.001) {
ShadowData data = shadows_data[int(ld.l_shadowid)];
float delta;
vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
vec3 T, B;
make_orthonormal_basis(L.xyz / L.w, T, B);
vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
rand.zw *= fast_sqrt(rand.y) * data.sh_blur;
/* We use the full l_vector.xyz so that the spread is minimize
* if the shading point is further away from the light source */
W = W + T * rand.z + B * rand.w;
if (ld.l_type == SUN) {
int scd_id = int(data.sh_data_start);
vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z);
float id = abs(4.0 - dot(weights, weights));
if (id > 3.0) {
return vec3(0.0);
}
/* Same factor as in get_cascade_world_distance(). */
float range = abs(data.sh_far - data.sh_near);
vec4 shpos = shadows_cascade_data[scd_id].shadowmat[int(id)] * vec4(W, 1.0);
float dist = shpos.z * range;
if (shpos.z > 1.0 || shpos.z < 0.0) {
return vec3(0.0);
}
ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id);
delta = get_depth_delta(dist, s);
}
else {
vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz;
float dist = length(cubevec);
cubevec /= dist;
ShadowSample s = sample_cube(cubevec, data.sh_tex_start);
delta = get_depth_delta(dist, s);
}
/* XXX : Removing Area Power. */
/* TODO : put this out of the shader. */
float falloff;
if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
if (ld.l_type == AREA_ELLIPSE) {
vis *= M_PI * 0.25;
}
vis *= 0.3 * 20.0 *
max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
vis /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
else if (ld.l_type == SUN) {
vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
vis *= M_2PI * 0.78; /* Matching cycles with point light. */
vis *= 0.082; /* XXX ad hoc, empirical */
falloff = dot(N, -ld.l_forward);
}
else {
vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
vis *= 1.5; /* XXX ad hoc, empirical */
vis /= (l_vector.w * l_vector.w);
falloff = dot(N, l_vector.xyz / l_vector.w);
}
// vis *= M_1_PI; /* Normalize */
/* Applying profile */
vis *= sss_profile(abs(delta) / scale);
/* No transmittance at grazing angle (hide artifacts) */
vis *= saturate(falloff * 2.0);
}
else {
vis = vec3(0.0);
}
return vis;
#endif
}

View File

@@ -148,10 +148,6 @@ void CLOSURE_NAME(vec3 N
,
out vec3 out_diff
#endif
#ifdef CLOSURE_SUBSURFACE
,
out vec3 out_trans
#endif
#ifdef CLOSURE_GLOSSY
,
out vec3 out_spec
@@ -170,10 +166,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 +222,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 +239,8 @@ 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, l_vector);
if (l_vis < 1e-8) {
continue;
@@ -249,10 +252,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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -279,6 +279,23 @@ void drw_state_set(DRWState state)
}
}
/* Shadow Bias */
{
int test;
if ((test = CHANGED_TO(DRW_STATE_SHADOW_OFFSET))) {
if (test == 1) {
glEnable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_POLYGON_OFFSET_LINE);
/* 2.0 Seems to be the lowest possible slope bias that works in every case. */
glPolygonOffset(2.0f, 1.0f);
}
else {
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
}
}
}
/* Clip Planes */
{
int test;

View File

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

View File

@@ -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);
@@ -100,7 +100,6 @@ void node_bsdf_principled(vec4 base_color,
sss_scalef,
ior,
out_diff,
out_trans,
out_spec,
out_refr,
ssr_spec);
@@ -116,24 +115,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;
@@ -318,7 +301,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);
@@ -341,7 +324,6 @@ void node_bsdf_principled_subsurface(vec4 base_color,
1.0,
sss_scalef,
out_diff,
out_trans,
out_spec,
ssr_spec);
@@ -349,24 +331,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;

View File

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

View File

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

View File

@@ -58,7 +58,10 @@ typedef struct Light {
char _pad2[2];
float clipsta, clipend;
float bias, soft, bleedbias, bleedexp;
float bias;
float soft DNA_DEPRECATED;
float bleedbias DNA_DEPRECATED;
float bleedexp DNA_DEPRECATED;
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 DNA_DEPRECATED;
float contact_thickness;
float spec_fac, att_dist;

View File

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

View File

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

View File

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