diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_render.py | 10 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_data.c | 3 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_effects.c | 111 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_engine.c | 12 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 50 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_private.h | 28 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/lamps_lib.glsl | 2 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl | 41 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 70 |
9 files changed, 265 insertions, 62 deletions
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 679a80aa6dc..40307a1d3bb 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -616,6 +616,7 @@ class RENDER_PT_clay_collection_settings(RenderButtonsPanel, Panel): col.prop(props, "ssao_attenuation") col.prop(props, "hair_brightness_randomness") + class RENDER_PT_eevee_poststack_settings(RenderButtonsPanel, Panel): bl_label = "Post Process Stack" COMPAT_ENGINES = {'BLENDER_EEVEE'} @@ -698,7 +699,14 @@ class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel): layout.active = props.volumetric_enable col = layout.column() - # to be completed + col.prop(props, "volumetric_start") + col.prop(props, "volumetric_end") + col.prop(props, "volumetric_samples") + col.prop(props, "volumetric_sample_distribution") + col.prop(props, "volumetric_lights") + col.prop(props, "volumetric_shadows") + col.prop(props, "volumetric_shadow_samples") + col.prop(props, "volumetric_colored_transmittance") classes = ( diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 8893a8c62e9..36d91c0cc28 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -61,6 +61,9 @@ static void eevee_scene_layer_data_free(void *storage) DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); + + /* Volumetrics */ + MEM_SAFE_FREE(sldata->volumetrics); } static void eevee_lamp_data_free(void *storage) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index a816fe8332a..602d4f272b8 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -134,7 +134,7 @@ static void eevee_motion_blur_camera_get_matrix_at_time( mul_m4_m4m4(r_mat, params.winmat, obmat); } -void EEVEE_effects_init(EEVEE_Data *vedata) +void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -403,29 +403,68 @@ void EEVEE_effects_init(EEVEE_Data *vedata) &tex, 1); if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) { - /* Integration result buffer(s) */ - if (false) { /* TODO check and free the framebuffer if config changes */ - /* Monocromatic transmittance in alpha */ - DRWFboTexture tex_vol = {&stl->g_data->volumetric, DRW_TEX_RGBA_16, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}; - - DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, - (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, - &tex_vol, 1); - } - else { - /* Transmittance is separated, No need for alpha and DRW_TEX_RGB_11_11_10 gives the same vram usage */ - /* Hint ! Could reuse this for transparency! */ - DRWFboTexture tex_vol[2] = {{&stl->g_data->volumetric, DRW_TEX_RGB_11_11_10, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}, - {&stl->g_data->volumetric_transmit, DRW_TEX_RGB_11_11_10, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}}; - - DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, - (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, - tex_vol, 2); - } - World *wo = scene->world; + + /* TODO: this will not be the case if we support object volumetrics */ if ((wo != NULL) && (wo->use_nodes) && (wo->nodetree != NULL)) { effects->enabled_effects |= EFFECT_VOLUMETRIC; + + if (sldata->volumetrics == NULL) { + sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo"); + } + + EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; + bool last_use_colored_transmit = volumetrics->use_colored_transmit; /* Save to compare */ + + volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); + volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); + + if (DRW_viewport_is_persp_get()) { + /* Negate */ + volumetrics->integration_start = -volumetrics->integration_start; + volumetrics->integration_end = -volumetrics->integration_end; + } + else { + const float clip_start = stl->g_data->viewvecs[0][2]; + const float clip_end = stl->g_data->viewvecs[1][2]; + volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start); + volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end); + } + + volumetrics->sample_distribution = BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution"); + volumetrics->integration_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_samples"); + volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); + + volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); + volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows"); + volumetrics->use_colored_transmit = BKE_collection_engine_property_value_get_bool(props, "volumetric_colored_transmittance"); + + if (last_use_colored_transmit != volumetrics->use_colored_transmit) { + if (fbl->volumetric_fb != NULL) { + DRW_framebuffer_free(fbl->volumetric_fb); + fbl->volumetric_fb = NULL; + } + } + + /* Integration result buffer(s) */ + if (volumetrics->use_colored_transmit == false) { + /* Monocromatic transmittance in alpha */ + DRWFboTexture tex_vol = {&stl->g_data->volumetric, DRW_TEX_RGBA_16, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}; + + DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, + (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, + &tex_vol, 1); + } + else { + /* Transmittance is separated, No need for alpha and DRW_TEX_RGB_11_11_10 gives the same vram usage */ + /* Hint ! Could reuse this for transparency! */ + DRWFboTexture tex_vol[2] = {{&stl->g_data->volumetric, DRW_TEX_RGB_11_11_10, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}, + {&stl->g_data->volumetric_transmit, DRW_TEX_RGB_11_11_10, DRW_TEX_MIPMAP | DRW_TEX_FILTER | DRW_TEX_TEMP}}; + + DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, + (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, + tex_vol, 2); + } } } } @@ -462,8 +501,12 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; struct World *wo = scene->world; /* Already checked non NULL */ + EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; + + struct GPUMaterial *mat = EEVEE_material_world_volume_get( + scene, wo, volumetrics->use_lights, volumetrics->use_volume_shadows, + false, volumetrics->use_colored_transmit); - struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); psl->volumetric_integrate_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_material_create(mat, psl->volumetric_integrate_ps); @@ -478,11 +521,14 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_int(grp, "grid_count", &sldata->probes->num_render_grid, 1); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "volume_start_end", &sldata->volumetrics->integration_start, 1); + DRW_shgroup_uniform_vec3(grp, "volume_samples", &sldata->volumetrics->integration_step_count, 1); DRW_shgroup_call_add(grp, quad, NULL); - if (false) { /* Monochromatic transmittance */ + if (volumetrics->use_colored_transmit == false) { /* Monochromatic transmittance */ psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_TRANSMISSION); grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_ps); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric); DRW_shgroup_call_add(grp, quad, NULL); @@ -490,12 +536,14 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) else { psl->volumetric_resolve_transmit_ps = DRW_pass_create("Volumetric Transmittance Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_MULTIPLY); grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_transmit_ps); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric_transmit); DRW_shgroup_call_add(grp, quad, NULL); psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); grp = DRW_shgroup_create(e_data.volumetric_upsample_sh, psl->volumetric_resolve_ps); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); DRW_shgroup_uniform_buffer(grp, "depthFull", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "volumetricBuffer", &stl->g_data->volumetric); DRW_shgroup_call_add(grp, quad, NULL); @@ -659,7 +707,7 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src) DRW_framebuffer_recursive_downsample(fbl->minmaxz_fb, stl->g_data->minmaxz, 6, &minmax_downsample_cb, vedata); } -void EEVEE_effects_do_volumetrics(EEVEE_Data *vedata) +void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -673,25 +721,26 @@ void EEVEE_effects_do_volumetrics(EEVEE_Data *vedata) /* Compute volumetric integration at halfres. */ DRW_framebuffer_texture_attach(fbl->volumetric_fb, stl->g_data->volumetric, 0, 0); - DRW_framebuffer_texture_attach(fbl->volumetric_fb, stl->g_data->volumetric_transmit, 1, 0); + if (sldata->volumetrics->use_colored_transmit) { + DRW_framebuffer_texture_attach(fbl->volumetric_fb, stl->g_data->volumetric_transmit, 1, 0); + } DRW_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_integrate_ps); /* Resolve at fullres */ DRW_framebuffer_texture_detach(dtxl->depth); DRW_framebuffer_bind(fbl->main); - if (false) { - DRW_draw_pass(psl->volumetric_resolve_ps); - } - else { + if (sldata->volumetrics->use_colored_transmit) { DRW_draw_pass(psl->volumetric_resolve_transmit_ps); - DRW_draw_pass(psl->volumetric_resolve_ps); } + DRW_draw_pass(psl->volumetric_resolve_ps); /* Restore */ DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); DRW_framebuffer_texture_detach(stl->g_data->volumetric); - DRW_framebuffer_texture_detach(stl->g_data->volumetric_transmit); + if (sldata->volumetrics->use_colored_transmit) { + DRW_framebuffer_texture_detach(stl->g_data->volumetric_transmit); + } } } diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index c72e1f03f4d..feee13b06f8 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -65,7 +65,7 @@ static void EEVEE_engine_init(void *ved) EEVEE_materials_init(stl); EEVEE_lights_init(sldata); EEVEE_lightprobes_init(sldata, vedata); - EEVEE_effects_init(vedata); + EEVEE_effects_init(sldata, vedata); } static void EEVEE_cache_init(void *vedata) @@ -161,7 +161,7 @@ static void EEVEE_draw_scene(void *vedata) DRW_draw_pass(psl->material_pass); /* Volumetrics */ - EEVEE_effects_do_volumetrics(vedata); + EEVEE_effects_do_volumetrics(sldata, vedata); /* Post Process */ EEVEE_draw_effects(vedata); @@ -191,6 +191,14 @@ static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPr props->subtype == IDP_GROUP_SUB_ENGINE_RENDER); BKE_collection_engine_property_add_bool(props, "volumetric_enable", false); + BKE_collection_engine_property_add_float(props, "volumetric_start", 0.1); + BKE_collection_engine_property_add_float(props, "volumetric_end", 100.0); + BKE_collection_engine_property_add_int(props, "volumetric_samples", 64); + BKE_collection_engine_property_add_float(props, "volumetric_sample_distribution", 0.8); + BKE_collection_engine_property_add_bool(props, "volumetric_lights", true); + BKE_collection_engine_property_add_bool(props, "volumetric_shadows", false); + BKE_collection_engine_property_add_int(props, "volumetric_shadow_samples", 16); + BKE_collection_engine_property_add_bool(props, "volumetric_colored_transmittance", true); BKE_collection_engine_property_add_bool(props, "gtao_enable", false); BKE_collection_engine_property_add_bool(props, "gtao_use_bent_normals", true); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index c0ddd977bbc..4cc8b5ed93c 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -209,6 +209,35 @@ static char *eevee_get_defines(int options) return str; } +static char *eevee_get_volume_defines(int options) +{ + char *str = NULL; + + BLI_assert(options < VAR_MAT_MAX); + + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_appendf(ds, SHADER_DEFINES); + BLI_dynstr_appendf(ds, "#define VOLUMETRICS\n"); + + if ((options & VAR_VOLUME_SHADOW) != 0) { + BLI_dynstr_appendf(ds, "#define VOLUME_SHADOW\n"); + } + if ((options & VAR_VOLUME_HOMO) != 0) { + BLI_dynstr_appendf(ds, "#define VOLUME_HOMOGENEOUS\n"); + } + if ((options & VAR_VOLUME_LIGHT) != 0) { + BLI_dynstr_appendf(ds, "#define VOLUME_LIGHTING\n"); + } + if ((options & VAR_VOLUME_COLOR) != 0) { + BLI_dynstr_appendf(ds, "#define COLOR_TRANSMITTANCE\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str; +} + static void add_standard_uniforms(DRWShadingGroup *shgrp, EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); @@ -406,20 +435,33 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor SHADER_DEFINES "#define WORLD_BACKGROUND\n"); } -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo) +struct GPUMaterial *EEVEE_material_world_volume_get( + struct Scene *scene, World *wo, + bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit) { const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_WORLD_VOLUME; + if (use_lights) options |= VAR_VOLUME_LIGHT; + if (is_homogeneous) options |= VAR_VOLUME_HOMO; + if (use_volume_shadows) options |= VAR_VOLUME_SHADOW; + if (use_color_transmit) options |= VAR_VOLUME_COLOR; + GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options); if (mat != NULL) { return mat; } - return GPU_material_from_nodetree( + + char *defines = eevee_get_volume_defines(options); + + mat = GPU_material_from_nodetree( scene, wo->nodetree, &wo->gpumaterial, engine, options, datatoc_background_vert_glsl, NULL, e_data.volume_shader_lib, - SHADER_DEFINES "#define VOLUMETRICS\n" - "#define COLOR_TRANSMITTANCE\n"); + defines); + + MEM_freeN(defines); + + return mat; } struct GPUMaterial *EEVEE_material_mesh_get( diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index b9cd3adfab2..286d833fca3 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -48,9 +48,14 @@ extern struct DrawEngineType draw_engine_eevee_type; /* World shader variations */ enum { - VAR_WORLD_BACKGROUND, - VAR_WORLD_PROBE, - VAR_WORLD_VOLUME, + VAR_VOLUME_SHADOW = (1 << 0), + VAR_VOLUME_HOMO = (1 << 1), + VAR_VOLUME_LIGHT = (1 << 2), + VAR_VOLUME_COLOR = (1 << 3), + + VAR_WORLD_BACKGROUND = 16, + VAR_WORLD_PROBE = 17, + VAR_WORLD_VOLUME = 18, }; /* Material shader variations */ @@ -181,6 +186,13 @@ typedef struct EEVEE_ShadowRender { float exponent; } EEVEE_ShadowRender; +/* ************ VOLUME DATA ************ */ +typedef struct EEVEE_VolumetricsInfo { + float integration_step_count, shadow_step_count, sample_distribution; + float integration_start, integration_end; + bool use_lights, use_volume_shadows, use_colored_transmit; +} EEVEE_VolumetricsInfo; + /* ************ LIGHT DATA ************* */ typedef struct EEVEE_LampsInfo { int num_light, cache_num_light; @@ -358,6 +370,9 @@ typedef struct EEVEE_SceneLayerData { struct GPUTexture *irradiance_rt; struct ListBase probe_queue; /* List of probes to update */ + + /* Volumetrics */ + struct EEVEE_VolumetricsInfo *volumetrics; } EEVEE_SceneLayerData; /* ************ OBJECT DATA ************ */ @@ -427,7 +442,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl void EEVEE_materials_cache_finish(EEVEE_Data *vedata); struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo); struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo); -struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo); +struct GPUMaterial *EEVEE_material_world_volume_get( + struct Scene *scene, struct World *wo, bool use_lights, bool use_volume_shadows, bool is_homogeneous, bool use_color_transmit); struct GPUMaterial *EEVEE_material_mesh_lightprobe_get(struct Scene *scene, Material *ma); struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals); struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, bool use_ao, bool use_bent_normals); @@ -453,10 +469,10 @@ void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) void EEVEE_lightprobes_free(void); /* eevee_effects.c */ -void EEVEE_effects_init(EEVEE_Data *vedata); +void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src); -void EEVEE_effects_do_volumetrics(EEVEE_Data *vedata); +void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_draw_effects(EEVEE_Data *vedata); void EEVEE_effects_free(void); diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl index ba1e0e89d28..061719b5685 100644 --- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl @@ -107,7 +107,7 @@ float light_visibility(LightData ld, vec3 W, vec4 l_vector) vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward)); } -#if !defined(VOLUMETRICS) || defined(SHADOWS) +#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW) /* shadowing */ if (ld.l_shadowid >= (MAX_SHADOW_MAP + MAX_SHADOW_CUBE)) { vis *= shadow_cascade(ld.l_shadowid, W); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index efc744f3ca4..916ff01b520 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -1,7 +1,19 @@ #ifdef VOLUMETRICS +#define VOLUMETRIC_INTEGRATION_MAX_STEP 256 +#define VOLUMETRIC_SHADOW_MAX_STEP 128 + uniform int light_count; +uniform vec2 volume_start_end; +uniform vec3 volume_samples; + +#define volume_start volume_start_end.x +#define volume_end volume_start_end.y + +#define volume_integration_steps volume_samples.x +#define volume_shadows_steps volume_samples.y +#define volume_sample_distribution volume_samples.z #ifdef COLOR_TRANSMITTANCE layout(location = 0) out vec4 outScattering; @@ -51,7 +63,7 @@ float phase_function_isotropic() float phase_function(vec3 v, vec3 l, float g) { -#ifndef VOLUME_ISOTROPIC +#ifndef VOLUME_ISOTROPIC /* TODO Use this flag when only isotropic closures are used */ /* Henyey-Greenstein */ float cos_theta = dot(v, l); g = clamp(g, -1.0 + 1e-3, 1.0 - 1e-3); @@ -97,12 +109,11 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, vec3 s_exti return exp(-s_extinction * l_vector.w); #else /* Heterogeneous volume shadows */ - const float numStep = 16.0; - float dd = l_vector.w / numStep; + float dd = l_vector.w / volume_shadows_steps; vec3 L = l_vector.xyz * l_vector.w; vec3 shadow = vec3(1.0); - for (float s = 0.5; s < (numStep - 0.1); s += 1.0) { - vec3 pos = ray_wpos + L * (s / numStep); + for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volume_shadows_steps - 0.1); s += 1.0) { + vec3 pos = ray_wpos + L * (s / volume_shadows_steps); vec3 s_extinction = participating_media_extinction(pos); shadow *= exp(-s_extinction * dd); } @@ -114,17 +125,15 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, vec3 s_exti #endif /* VOLUME_SHADOW */ } -float find_next_step(float near, float far, float noise, int iter, int iter_count) +float find_next_step(float iter, float noise) { - const float lambda = 0.8f; /* TODO : Parameter */ - - float progress = (float(iter) + noise) / float(iter_count); + float progress = (iter + noise) / volume_integration_steps; - float linear_split = mix(near, far, progress); + float linear_split = mix(volume_start, volume_end, progress); if (ProjectionMatrix[3][3] == 0.0) { - float exp_split = near * pow(far / near, progress); - return mix(linear_split, exp_split, lambda); + float exp_split = volume_start * pow(volume_end / volume_start, progress); + return mix(linear_split, exp_split, volume_sample_distribution); } else { return linear_split; @@ -169,11 +178,9 @@ void main() float rand = texture(utilTex, vec3(gl_FragCoord.xy / LUT_SIZE, 2.0)).r; /* Less noisy but noticeable patterns, could work better with temporal AA. */ // float rand = (1.0 / 16.0) * float(((int(gl_FragCoord.x + gl_FragCoord.y) & 0x3) << 2) + (int(gl_FragCoord.x) & 0x3)); - float near = get_view_z_from_depth(0.0); - float far = get_view_z_from_depth(1.0); - float dist = near; - for (int i = 1; i < 64; ++i) { - float new_dist = find_next_step(near, far, rand, i, 64); + float dist = volume_start; + for (float i = 0.5; i < VOLUMETRIC_INTEGRATION_MAX_STEP && i < (volume_integration_steps - 0.1); ++i) { + float new_dist = find_next_step(rand, i); float step = dist - new_dist; /* Marching step */ dist = new_dist; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8ff88af2df4..09a075cb128 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2613,6 +2613,14 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(motion_blur_enable) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(motion_blur_samples) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(motion_blur_shutter) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_enable) +RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_start) +RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_end) +RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_samples) +RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(volumetric_sample_distribution) +RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_lights) +RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_shadows) +RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_shadow_samples) +RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_colored_transmittance) /* object engine */ RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire) @@ -6175,6 +6183,68 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_start_get", + "rna_LayerEngineSettings_Eevee_volumetric_start_set", NULL); + RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_end_get", + "rna_LayerEngineSettings_Eevee_volumetric_end_set", NULL); + RNA_def_property_ui_text(prop, "End", "End distance of the volumetric effect"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_samples_get", + "rna_LayerEngineSettings_Eevee_volumetric_samples_set", NULL); + RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_range(prop, 1, 256); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_sample_distribution_get", + "rna_LayerEngineSettings_Eevee_volumetric_sample_distribution_set", NULL); + RNA_def_property_ui_text(prop, "Exponential Sampling", "Distribute more samples closer to the camera"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_lights", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_lights_get", + "rna_LayerEngineSettings_Eevee_volumetric_lights_set"); + RNA_def_property_ui_text(prop, "Volumetric Lighting", "Enable scene lamps interactions with volumetrics"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_shadows", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_shadows_get", + "rna_LayerEngineSettings_Eevee_volumetric_shadows_set"); + RNA_def_property_ui_text(prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_shadow_samples_get", + "rna_LayerEngineSettings_Eevee_volumetric_shadow_samples_set", NULL); + RNA_def_property_range(prop, 1, 128); + RNA_def_property_ui_text(prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + + prop = RNA_def_property(srna, "volumetric_colored_transmittance", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_colored_transmittance_get", + "rna_LayerEngineSettings_Eevee_volumetric_colored_transmittance_set"); + RNA_def_property_ui_text(prop, "Colored transmittance", "Enable wavelength dependant volumetric transmittance"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + /* Ambient Occlusion */ prop = RNA_def_property(srna, "gtao_enable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_enable_get", |