diff options
14 files changed, 358 insertions, 56 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 9c806f26fda..8339b6b8720 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -137,6 +137,7 @@ data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index d1cd1b1440c..d5582a498a4 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -55,6 +55,7 @@ static void eevee_view_layer_data_free(void *storage) DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); + DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 32b5023c65e..a83562e81ce 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -47,11 +47,13 @@ #include "ED_screen.h" #define IRRADIANCE_POOL_SIZE 1024 +#define HAMMERSLEY_SIZE 1024 static struct { struct GPUShader *probe_default_sh; struct GPUShader *probe_filter_glossy_sh; struct GPUShader *probe_filter_diffuse_sh; + struct GPUShader *probe_filter_visibility_sh; struct GPUShader *probe_grid_fill_sh; struct GPUShader *probe_grid_display_sh; struct GPUShader *probe_planar_display_sh; @@ -62,7 +64,6 @@ static struct { struct GPUTexture *planar_pool_placeholder; struct GPUTexture *depth_placeholder; struct GPUTexture *depth_array_placeholder; - struct GPUTexture *cube_face_depth; struct GPUTexture *cube_face_minmaxz; int update_world; @@ -73,6 +74,7 @@ extern char datatoc_background_vert_glsl[]; extern char datatoc_default_world_frag_glsl[]; extern char datatoc_lightprobe_filter_glossy_frag_glsl[]; extern char datatoc_lightprobe_filter_diffuse_frag_glsl[]; +extern char datatoc_lightprobe_filter_visibility_frag_glsl[]; extern char datatoc_lightprobe_geom_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lightprobe_planar_display_frag_glsl[]; @@ -159,6 +161,7 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) { + bool update_all = false; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); @@ -176,7 +179,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda e_data.probe_filter_glossy_sh = DRW_shader_create( datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, - "#define HAMMERSLEY_SIZE 1024\n" + "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" "#define NOISE_SIZE 64\n"); e_data.probe_default_sh = DRW_shader_create( @@ -200,7 +203,21 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda #elif defined(IRRADIANCE_HL2) "#define IRRADIANCE_HL2\n" #endif - "#define HAMMERSLEY_SIZE 1024\n" + "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" + "#define NOISE_SIZE 64\n"); + + MEM_freeN(shader_str); + + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_visibility_frag_glsl); + shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen( + shader_str, + "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n" "#define NOISE_SIZE 64\n"); MEM_freeN(shader_str); @@ -260,7 +277,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda datatoc_lightprobe_planar_downsample_frag_glsl, NULL); - e_data.hammersley = create_hammersley_sample_texture(1024); + e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE); } if (!sldata->probes) { @@ -275,21 +292,15 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda } int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces"); - /* Update all probes if number of bounces mismatch. */ if (sldata->probes->num_bounce != prop_bounce_num) { - e_data.update_world |= PROBE_UPDATE_ALL; - sldata->probes->updated_bounce = 0; - sldata->probes->grid_initialized = false; + sldata->probes->num_bounce = prop_bounce_num; + update_all = true; } - sldata->probes->num_bounce = prop_bounce_num; int prop_cubemap_res = BKE_collection_engine_property_value_get_int(props, "gi_cubemap_resolution"); if (sldata->probes->cubemap_res != prop_cubemap_res) { sldata->probes->cubemap_res = prop_cubemap_res; - - e_data.update_world |= PROBE_UPDATE_ALL; - sldata->probes->updated_bounce = 0; - sldata->probes->grid_initialized = false; + update_all = true; sldata->probes->target_size = prop_cubemap_res >> 1; @@ -297,25 +308,27 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); } - /* Setup Render Target Cubemap */ - - /* We do this detach / attach dance to not generate an invalid framebuffer (mixed cubemap / 2D map) */ - if (sldata->probe_rt) { - /* XXX Silly,TODO Cleanup this mess */ - DRW_framebuffer_texture_detach(sldata->probe_rt); + int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution"); + if (sldata->probes->irradiance_vis_size != visibility_res) { + sldata->probes->irradiance_vis_size = visibility_res; + update_all = true; } - DRWFboTexture tex_probe = {&e_data.cube_face_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP}; - DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, &tex_probe, 1); + if (update_all) { + e_data.update_world |= PROBE_UPDATE_ALL; + sldata->probes->updated_bounce = 0; + sldata->probes->grid_initialized = false; + } + /* Setup Render Target Cubemap */ if (!sldata->probe_rt) { + sldata->probe_depth_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_DEPTH_24, 0, NULL); sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); } - if (sldata->probe_rt) { - /* XXX Silly,TODO Cleanup this mess */ - DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); - } + DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, 0}, + {&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}}; + DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, tex_probe, 2); /* Minmaxz Pyramid */ // DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP}; @@ -435,10 +448,29 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat } { + psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute); + DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1); + DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1); + DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "storedTexelSize", &sldata->probes->texel_size, 1); + DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1); + DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); + DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt); + + struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call_add(grp, geom, NULL); + } + + { psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_fill_sh, psl->probe_grid_fill); - DRW_shgroup_uniform_buffer(grp, "gridTexture", &sldata->irradiance_pool); + DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call_add(grp, geom, NULL); @@ -751,6 +783,13 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x); + /* Visibility bias */ + egrid->visibility_bias = 0.05f * probe->vis_bias; + egrid->visibility_bleed = probe->vis_bleedbias; + egrid->visibility_range = max_ff(max_ff(len_v3(egrid->increment_x), + len_v3(egrid->increment_y)), + len_v3(egrid->increment_z)) + 1.0f; + /* Debug Display */ if (BKE_object_is_visible(ob) && DRW_state_draw_support() && @@ -825,16 +864,18 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* we need a signed format for Spherical Harmonics */ int irradiance_format = DRW_TEX_RGBA_16; #else - int irradiance_format = DRW_TEX_RGB_11_11_10; + int irradiance_format = DRW_TEX_RGBA_8; #endif /* TODO Allocate bigger storage if needed. */ if (!sldata->irradiance_pool || !sldata->irradiance_rt) { if (!sldata->irradiance_pool) { - sldata->irradiance_pool = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL); + sldata->irradiance_pool = DRW_texture_create_2D_array(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, 2, + irradiance_format, DRW_TEX_FILTER, NULL); } if (!sldata->irradiance_rt) { - sldata->irradiance_rt = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL); + sldata->irradiance_rt = DRW_texture_create_2D_array(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, 2, + irradiance_format, DRW_TEX_FILTER, NULL); } pinfo->num_render_grid = 0; pinfo->updated_bounce = 0; @@ -953,7 +994,9 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, } /* Diffuse filter probe_rt to irradiance_pool at index probe_idx */ -static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset) +static void diffuse_filter_probe( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset, + float clipsta, float clipend, float vis_range, float vis_blur) { EEVEE_LightProbesInfo *pinfo = sldata->probes; @@ -994,6 +1037,26 @@ static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]); DRW_draw_pass(psl->probe_diffuse_compute); + /* Compute visibility */ + pinfo->samples_ct = 512.0f; /* TODO refine */ + pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; + pinfo->shres = pinfo->irradiance_vis_size; + pinfo->visibility_range = vis_range; + pinfo->visibility_blur = vis_blur; + pinfo->near_clip = -clipsta; + pinfo->far_clip = -clipend; + pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size; + + cell_per_row = IRRADIANCE_POOL_SIZE / pinfo->irradiance_vis_size; + x = pinfo->irradiance_vis_size * (offset % cell_per_row); + y = pinfo->irradiance_vis_size * (offset / cell_per_row); + + DRW_framebuffer_texture_detach(sldata->irradiance_rt); + DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 1, 0); + + DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size); + DRW_draw_pass(psl->probe_visibility_compute); + /* reattach to have a valid framebuffer. */ DRW_framebuffer_texture_detach(sldata->irradiance_rt); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); @@ -1044,8 +1107,8 @@ static void render_scene_to_probe( /* Detach to rebind the right cubeface. */ DRW_framebuffer_bind(sldata->probe_fb); - DRW_framebuffer_texture_attach(sldata->probe_fb, e_data.cube_face_depth, 0, 0); DRW_framebuffer_texture_detach(sldata->probe_rt); + DRW_framebuffer_texture_detach(sldata->probe_depth_rt); for (int i = 0; i < 6; ++i) { float viewmat[4][4], persmat[4][4]; float viewinv[4][4], persinv[4][4]; @@ -1068,6 +1131,7 @@ static void render_scene_to_probe( EEVEE_draw_shadows(sldata, psl); DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0); + DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, i, 0); DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size); DRW_framebuffer_clear(false, true, false, NULL, 1.0); @@ -1078,7 +1142,7 @@ static void render_scene_to_probe( DRW_draw_pass(psl->probe_background); - // EEVEE_create_minmax_buffer(vedata, e_data.cube_face_depth); + // EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt); /* Rebind Planar FB */ DRW_framebuffer_bind(sldata->probe_fb); @@ -1089,9 +1153,10 @@ static void render_scene_to_probe( DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ DRW_framebuffer_texture_detach(sldata->probe_rt); + DRW_framebuffer_texture_detach(sldata->probe_depth_rt); } DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); - DRW_framebuffer_texture_detach(e_data.cube_face_depth); + DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0); DRW_viewport_matrix_override_unset(DRW_MAT_PERS); DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); @@ -1212,6 +1277,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p /* Detach to rebind the right cubeface. */ DRW_framebuffer_bind(sldata->probe_fb); DRW_framebuffer_texture_detach(sldata->probe_rt); + DRW_framebuffer_texture_detach(sldata->probe_depth_rt); for (int i = 0; i < 6; ++i) { float viewmat[4][4], persmat[4][4]; float viewinv[4][4], persinv[4][4]; @@ -1237,6 +1303,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p DRW_framebuffer_texture_detach(sldata->probe_rt); } DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); + DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0); DRW_viewport_matrix_override_unset(DRW_MAT_PERS); DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); @@ -1276,7 +1343,7 @@ static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *v glossy_filter_probe(sldata, vedata, psl, 0); } if (e_data.update_world & PROBE_UPDATE_GRID) { - diffuse_filter_probe(sldata, vedata, psl, 0); + diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0); SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); DRW_framebuffer_texture_detach(sldata->probe_pool); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); @@ -1465,7 +1532,8 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); } render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend); - diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id); + diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id, + prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur); /* To see what is going on. */ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); /* Restore */ @@ -1543,6 +1611,7 @@ void EEVEE_lightprobes_free(void) DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); + DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh); DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh); DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 41564bb2703..c25ab1e7859 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -374,6 +374,7 @@ static void add_standard_uniforms( DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1); DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index dc99d941db8..36a6d3fb1d0 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -141,6 +141,7 @@ typedef struct EEVEE_PassList { struct DRWPass *probe_background; struct DRWPass *probe_glossy_compute; struct DRWPass *probe_diffuse_compute; + struct DRWPass *probe_visibility_compute; struct DRWPass *probe_grid_fill; struct DRWPass *probe_display; struct DRWPass *probe_planar_downsample_ps; @@ -369,6 +370,7 @@ typedef struct EEVEE_LightGrid { float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */ float increment_y[3], level_bias; float increment_z[3], pad4; + float visibility_bias, visibility_bleed, visibility_range, pad5; } EEVEE_LightGrid; typedef struct EEVEE_PlanarReflection { @@ -391,6 +393,7 @@ typedef struct EEVEE_LightProbesInfo { int num_bounce; int cubemap_res; int target_size; + int irradiance_vis_size; int grid_initialized; /* Actual number of probes that have datas. */ int num_render_cube; @@ -402,9 +405,13 @@ typedef struct EEVEE_LightProbesInfo { float padding_size; float samples_ct; float invsamples_ct; + float near_clip; + float far_clip; float roughness; float lodfactor; float lod_rt_max, lod_cube_max, lod_planar_max; + float visibility_range; + float visibility_blur; int shres; int shnbr; bool specular_toggle; @@ -550,6 +557,7 @@ typedef struct EEVEE_ViewLayerData { struct GPUFrameBuffer *probe_filter_fb; struct GPUTexture *probe_rt; + struct GPUTexture *probe_depth_rt; struct GPUTexture *probe_pool; struct GPUTexture *irradiance_pool; struct GPUTexture *irradiance_rt; diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index dfb88572cf8..dae4503dc32 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -86,8 +86,8 @@ static void eevee_create_shader_volumes(void) ds_frag = BLI_dynstr_new(); BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index aecb1e6dde4..37ed2235c6f 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -432,6 +432,78 @@ vec3 normal_decode(vec2 enc, vec3 view) return n; } +/* ---- RGBM (shared multiplier) encoding ---- */ +/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */ + +/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */ +#define RGBM_MAX_RANGE 512.0 + +vec4 rgbm_encode(vec3 rgb) +{ + float maxRGB = max_v3(rgb); + float M = maxRGB / RGBM_MAX_RANGE; + M = ceil(M * 255.0) / 255.0; + return vec4(rgb / (M * RGBM_MAX_RANGE), M); +} + +vec3 rgbm_decode(vec4 data) +{ + return data.rgb * (data.a * RGBM_MAX_RANGE); +} + +/* ---- RGBE (shared exponent) encoding ---- */ +vec4 rgbe_encode(vec3 rgb) +{ + float maxRGB = max_v3(rgb); + float fexp = ceil(log2(maxRGB)); + return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0); +} + +vec3 rgbe_decode(vec4 data) +{ + float fexp = data.a * 255.0 - 128.0; + return data.rgb * exp2(fexp); +} + +#if 1 +#define irradiance_encode rgbe_encode +#define irradiance_decode rgbe_decode +#else /* No ecoding (when using floating point format) */ +#define irradiance_encode(X) (X).rgbb +#define irradiance_decode(X) (X).rgb +#endif + +/* Irradiance Visibility Encoding */ +#if 1 +vec4 visibility_encode(vec2 accum, float range) +{ + accum /= range; + + vec4 data; + data.x = fract(accum.x); + data.y = floor(accum.x) / 255.0; + data.z = fract(accum.y); + data.w = floor(accum.y) / 255.0; + + return data; +} + +vec2 visibility_decode(vec4 data, float range) +{ + return (data.xz + data.yw * 255.0) * range; +} +#else /* No ecoding (when using floating point format) */ +vec4 visibility_encode(vec2 accum, float range) +{ + return accum.xyxy; +} + +vec2 visibility_decode(vec4 data, float range) +{ + return data.xy; +} +#endif + /* Fresnel monochromatic, perfect mirror */ float F_eta(float eta, float cos_theta) { diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index f58dac6c0a0..8cb5a66290d 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -90,4 +90,18 @@ vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B) return tangent_to_world(Ht, N, T, B); } + +vec3 sample_cone(float nsample, float angle, vec3 N, vec3 T, vec3 B) +{ + vec3 Xi = hammersley_3d(nsample); + + float z = cos(angle * Xi.x); /* cos theta */ + float r = sqrt( 1.0f - z*z ); /* sin theta */ + float x = r * Xi.y; + float y = r * Xi.z; + + vec3 Ht = vec3(x, y, z); + + return tangent_to_world(Ht, N, T, B); +} #endif
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl index 95e7af41398..2555d413da9 100644 --- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl @@ -1,5 +1,6 @@ -uniform sampler2D irradianceGrid; +uniform sampler2DArray irradianceGrid; +uniform int irradianceVisibilitySize; #define IRRADIANCE_LIB @@ -36,7 +37,7 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) uvs += vec2(cell_co) / vec2(textureSize(irradianceGrid, 0)); IrradianceData ir; - ir.color = texture(irradianceGrid, uvs).rgb; + ir.color = texture(irradianceGrid, vec3(uvs, 0.0)).rgb; #elif defined(IRRADIANCE_SH_L2) @@ -48,15 +49,15 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) ivec3 ofs = ivec3(0, 1, 2); IrradianceData ir; - ir.shcoefs[0] = texelFetch(irradianceGrid, cell_co + ofs.xx, 0).rgb; - ir.shcoefs[1] = texelFetch(irradianceGrid, cell_co + ofs.yx, 0).rgb; - ir.shcoefs[2] = texelFetch(irradianceGrid, cell_co + ofs.zx, 0).rgb; - ir.shcoefs[3] = texelFetch(irradianceGrid, cell_co + ofs.xy, 0).rgb; - ir.shcoefs[4] = texelFetch(irradianceGrid, cell_co + ofs.yy, 0).rgb; - ir.shcoefs[5] = texelFetch(irradianceGrid, cell_co + ofs.zy, 0).rgb; - ir.shcoefs[6] = texelFetch(irradianceGrid, cell_co + ofs.xz, 0).rgb; - ir.shcoefs[7] = texelFetch(irradianceGrid, cell_co + ofs.yz, 0).rgb; - ir.shcoefs[8] = texelFetch(irradianceGrid, cell_co + ofs.zz, 0).rgb; + ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb; + ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb; + ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb; + ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb; + ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb; + ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb; + ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb; + ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb; + ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb; #else /* defined(IRRADIANCE_HL2) */ @@ -68,15 +69,50 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) ivec3 is_negative = ivec3(step(0.0, -N)); IrradianceData ir; - ir.cubesides[0] = texelFetch(irradianceGrid, cell_co + ivec2(0, is_negative.x), 0).rgb; - ir.cubesides[1] = texelFetch(irradianceGrid, cell_co + ivec2(1, is_negative.y), 0).rgb; - ir.cubesides[2] = texelFetch(irradianceGrid, cell_co + ivec2(2, is_negative.z), 0).rgb; + ir.cubesides[0] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0)); + ir.cubesides[1] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0)); + ir.cubesides[2] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0)); #endif return ir; } +float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range) +{ + /* Keep in sync with diffuse_filter_probe() */ + ivec2 cell_co = ivec2(irradianceVisibilitySize); + int cell_per_row = textureSize(irradianceGrid, 0).x / irradianceVisibilitySize; + cell_co.x *= (cell) % cell_per_row; + cell_co.y *= (cell) / cell_per_row; + + vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy); + vec2 co = vec2(cell_co) * texel_size; + + vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize))); + uv *= vec2(irradianceVisibilitySize) * texel_size; + + vec4 data = texture(irradianceGrid, vec3(co + uv, 1.0)); + + /* Decoding compressed data */ + vec2 moments = visibility_decode(data, range); + + /* Doing chebishev test */ + float variance = abs(moments.x * moments.x - moments.y); + variance = max(variance, bias / 10.0); + + float d = dist - moments.x; + float p_max = variance / (variance + d * d); + + /* Increase contrast in the weight by squaring it */ + p_max *= p_max; + + /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */ + p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0); + + return (dist <= moments.x) ? 1.0 : p_max; +} + /* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */ vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4]) { diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl index 0b97548c8df..eb4315c93a3 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl @@ -192,6 +192,6 @@ void main() } } - FragColor = vec4(out_radiance / weight, 1.0); + FragColor = irradiance_encode(out_radiance / weight); #endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl new file mode 100644 index 00000000000..0727e73f507 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl @@ -0,0 +1,88 @@ + +uniform samplerCube probeDepth; +uniform int outputSize; +uniform float lodFactor; +uniform float storedTexelSize; +uniform float lodMax; +uniform float nearClip; +uniform float farClip; +uniform float visibilityRange; +uniform float visibilityBlur; + +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; +} + +float linear_depth(float z) +{ + return (nearClip * farClip) / (z * (nearClip - farClip) + farClip); +} + +float get_world_distance(float depth, vec3 cos) +{ + float is_background = step(1.0, depth); + depth = linear_depth(depth); + depth += 1e1 * is_background; + cos = normalize(abs(cos)); + float cos_vec = max(cos.x, max(cos.y, cos.z)); + return depth / cos_vec; +} + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy) % ivec2(outputSize); + + vec3 cos; + + cos.xy = (vec2(texel) + 0.5) * storedTexelSize; + + /* 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)); + + vec3 T, B; + make_orthonormal_basis(cos, T, B); /* Generate tangent space */ + + vec2 accum = vec2(0.0); + + for (float i = 0; i < sampleCount; i++) { + vec3 sample = sample_cone(i, M_PI_2 * visibilityBlur, cos, T, B); + float depth = texture(probeDepth, sample).r; + depth = get_world_distance(depth, sample); + accum += vec2(depth, depth * depth); + } + + accum *= invSampleCount; + accum = abs(accum); + + /* Encode to normalized RGBA 8 */ + FragColor = visibility_encode(accum, visibilityRange); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl index cea1ca5e7b0..c9e66ceffb2 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl @@ -1,4 +1,4 @@ -uniform sampler2D gridTexture; +uniform sampler2DArray irradianceGrid; out vec4 FragColor; @@ -12,7 +12,7 @@ void main() const ivec2 data_size = ivec2(3, 2); #endif ivec2 coord = ivec2(gl_FragCoord.xy) % data_size; - FragColor = texelFetch(gridTexture, coord, 0); + FragColor = texelFetch(irradianceGrid, ivec3(coord, 0), 0); if (any(greaterThanEqual(ivec2(gl_FragCoord.xy), data_size))) { FragColor = vec4(0.0, 0.0, 0.0, 1.0); diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index 834bacc118b..e914228aded 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -49,6 +49,7 @@ struct GridData { vec4 ws_increment_x_atten_bias; /* world space vector between 2 opposite cells */ vec4 ws_increment_y_lvl_bias; vec4 ws_increment_z; + vec4 vis_bias_bleed_range; }; #define g_corner ws_corner_atten_scale.xyz @@ -60,6 +61,9 @@ struct GridData { #define g_increment_z ws_increment_z.xyz #define g_resolution resolution_offset.xyz #define g_offset resolution_offset.w +#define g_vis_bias vis_bias_bleed_range.x +#define g_vis_bleed vis_bias_bleed_range.y +#define g_vis_range vis_bias_bleed_range.z #ifndef MAX_PROBE #define MAX_PROBE 1 @@ -227,14 +231,18 @@ vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos) gd.g_increment_y * cell_cos.y + gd.g_increment_z * cell_cos.z); - // vec3 ws_point_to_cell = ws_cell_location - W; - // vec3 ws_light = normalize(ws_point_to_cell); + vec3 ws_point_to_cell = ws_cell_location - W; + float ws_dist_point_to_cell = length(ws_point_to_cell); + vec3 ws_light = ws_point_to_cell / ws_dist_point_to_cell; vec3 trilinear = mix(1 - trilinear_weight, trilinear_weight, offset); float weight = trilinear.x * trilinear.y * trilinear.z; + /* Precomputed visibility */ + weight *= load_visibility_cell(cell, ws_light, ws_dist_point_to_cell, gd.g_vis_bias, gd.g_vis_bleed, gd.g_vis_range); + /* Smooth backface test */ - // weight *= sqrt(max(0.002, dot(ws_light, N))); + weight *= sqrt(max(0.002, dot(ws_light, N))); /* Avoid zero weight */ weight = max(0.00001, weight); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index b3f5e8b60ad..1376c53d633 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -128,12 +128,16 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v #ifdef IRRADIANCE_LIB vec3 irradiance_volumetric(vec3 wpos) { +#ifdef IRRADIANCE_HL2 IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0)); vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2]; ir_data = load_irradiance_cell(0, vec3(-1.0)); irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2]; irradiance *= 0.16666666; /* 1/6 */ return irradiance; +#else + return vec3(0.0); +#endif } #endif |