diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_lightprobes.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lightprobes.c | 1934 |
1 files changed, 718 insertions, 1216 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index a45d69794f3..691d6ffe6eb 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -20,7 +20,7 @@ */ /** \file eevee_lightprobes.c - * \ingroup DNA + * \ingroup draw_engine */ #include "DRW_render.h" @@ -46,27 +46,14 @@ #include "DEG_depsgraph_query.h" #include "eevee_engine.h" +#include "eevee_lightcache.h" #include "eevee_private.h" #include "ED_screen.h" -/* Rounded to nearest PowerOfTwo */ -#if defined(IRRADIANCE_SH_L2) -#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ -#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */ -#elif defined(IRRADIANCE_CUBEMAP) -#define IRRADIANCE_SAMPLE_SIZE_X 8 -#define IRRADIANCE_SAMPLE_SIZE_Y 8 -#elif defined(IRRADIANCE_HL2) -#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */ -#define IRRADIANCE_SAMPLE_SIZE_Y 2 -#endif +#include "WM_api.h" +#include "WM_types.h" -#define IRRADIANCE_MAX_POOL_LAYER 256 /* OpenGL 3.3 core requirement, can be extended but it's already very big */ -#define IRRADIANCE_MAX_POOL_SIZE 1024 -#define MAX_IRRADIANCE_SAMPLES \ - (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \ - (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y) #define HAMMERSLEY_SIZE 1024 static struct { @@ -87,8 +74,8 @@ static struct { struct GPUTexture *depth_array_placeholder; struct GPUTexture *cube_face_minmaxz; - struct Gwn_VertFormat *format_probe_display_cube; - struct Gwn_VertFormat *format_probe_display_planar; + struct GPUVertFormat *format_probe_display_cube; + struct GPUVertFormat *format_probe_display_planar; } e_data = {NULL}; /* Engine data */ extern char datatoc_background_vert_glsl[]; @@ -120,19 +107,30 @@ extern GlobalsUboStorage ts; /* *********** FUNCTIONS *********** */ -static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3]) +/* TODO find a better way than this. This does not support dupli objects if + * the original object is hidden. */ +bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data) { - /* Compute how many irradiance samples we can store per visibility sample. */ - int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) * - (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y); + EEVEE_ObjectEngineData *oed = (EEVEE_ObjectEngineData *)user_data; + + /* test disabled if group is NULL */ + if (oed->test_data->collection == NULL) + return vis_in; + + if (oed->test_data->cached == false) + oed->ob_vis_dirty = true; + + /* early out, don't need to compute ob_vis yet. */ + if (vis_in == false) + return vis_in; - /* The irradiance itself take one layer, hence the +1 */ - int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER); + if (oed->ob_vis_dirty) { + oed->ob_vis_dirty = false; + oed->ob_vis = BKE_collection_has_object_recursive(oed->test_data->collection, oed->ob); + oed->ob_vis = (oed->test_data->invert) ? !oed->ob_vis : oed->ob_vis; + } - int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1)); - r_size[0] = visibility_size * max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); - r_size[1] = visibility_size * max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size))); - r_size[2] = layer_ct; + return vis_in && oed->ob_vis; } static struct GPUTexture *create_hammersley_sample_texture(int samples) @@ -156,11 +154,11 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples) static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) { + EEVEE_TextureList *txl = vedata->txl; + /* XXX TODO OPTIMISATION : This is a complete waist of texture memory. * Instead of allocating each planar probe for each viewport, * only alloc them once using the biggest viewport resolution. */ - EEVEE_TextureList *txl = vedata->txl; - const float *viewport_size = DRW_viewport_size_get(); /* TODO get screen percentage from layer setting */ @@ -275,7 +273,7 @@ static void lightprobe_shaders_init(void) datatoc_common_view_lib_glsl, datatoc_lightprobe_cube_display_vert_glsl); - e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL); + e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, SHADER_DEFINES); MEM_freeN(vert_str); MEM_freeN(shader_str); @@ -302,86 +300,132 @@ static void lightprobe_shaders_init(void) e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE); } -void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) +void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - bool update_all = false; + EEVEE_StorageList *stl = vedata->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - /* Shaders */ if (!e_data.probe_filter_glossy_sh) { lightprobe_shaders_init(); } + if ((scene_eval->eevee.light_cache == NULL) && + (sldata->fallback_lightcache == NULL)) + { +#if defined(IRRADIANCE_SH_L2) + int grid_res = 4; +#elif defined(IRRADIANCE_CUBEMAP) + int grid_res = 8; +#elif defined(IRRADIANCE_HL2) + int grid_res = 4; +#endif + int cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(scene_eval->eevee.gi_cubemap_resolution); + int vis_res = scene_eval->eevee.gi_visibility_resolution; + + sldata->fallback_lightcache = EEVEE_lightcache_create(1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1}); + } + + stl->g_data->light_cache = (scene_eval->eevee.light_cache) ? scene_eval->eevee.light_cache : sldata->fallback_lightcache; + + EEVEE_lightcache_load(stl->g_data->light_cache); + if (!sldata->probes) { sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo"); - sldata->probes->grid_initialized = false; sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL); sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL); sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL); } - /* Only start doing probes if all materials have finished compiling. */ - sldata->probes->all_materials_updated = true; + common_data->prb_num_planar = 0; + common_data->prb_num_render_cube = 1; + common_data->prb_num_render_grid = 1; common_data->spec_toggle = true; common_data->ssr_toggle = true; common_data->sss_toggle = true; - int prop_bounce_num = scene_eval->eevee.gi_diffuse_bounces; - if (sldata->probes->num_bounce != prop_bounce_num) { - sldata->probes->num_bounce = prop_bounce_num; - update_all = true; + /* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */ + if (!e_data.planar_pool_placeholder) { + e_data.planar_pool_placeholder = DRW_texture_create_2D_array(1, 1, 1, GPU_RGBA8, DRW_TEX_FILTER, NULL); } +} - int prop_cubemap_res = scene_eval->eevee.gi_cubemap_resolution; - if (sldata->probes->cubemap_res != prop_cubemap_res) { - sldata->probes->cubemap_res = prop_cubemap_res; - update_all = true; +/* Only init the passes usefull for rendering the light cache. */ +void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPUTexture *rt_color, GPUTexture *rt_depth) +{ + EEVEE_PassList *psl = vedata->psl; + LightCache *light_cache = vedata->stl->g_data->light_cache; + EEVEE_LightProbesInfo *pinfo = sldata->probes; - sldata->probes->target_size = prop_cubemap_res >> 1; + { + psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR); - DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt); - DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); - DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute); + DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1); + DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1); + DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); + DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); + DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1); + DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1); + DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); + // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); + DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } - const int visibility_res = scene_eval->eevee.gi_visibility_resolution; - if (common_data->prb_irradiance_vis_size != visibility_res) { - common_data->prb_irradiance_vis_size = visibility_res; - update_all = true; - } + { + psl->probe_diffuse_compute = DRW_pass_create("LightProbe Diffuse Compute", DRW_STATE_WRITE_COLOR); - if (update_all) { - sldata->probes->update_world |= PROBE_UPDATE_ALL; - sldata->probes->updated_bounce = 0; - sldata->probes->grid_initialized = false; - } + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute); +#ifdef IRRADIANCE_SH_L2 + DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1); +#else + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1); + DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); + DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); +#endif + DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); + DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color); - /* Setup Render Target Cubemap */ - if (!sldata->probe_rt) { - sldata->probe_depth_rt = DRW_texture_create_cube(sldata->probes->target_size, GPU_DEPTH_COMPONENT24, 0, NULL); - sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call_add(grp, geom, NULL); } - for (int i = 0; i < 6; ++i) { - GPU_framebuffer_ensure_config(&sldata->probe_face_fb[i], { - GPU_ATTACHMENT_TEXTURE_CUBEFACE(sldata->probe_depth_rt, i), - GPU_ATTACHMENT_TEXTURE_CUBEFACE(sldata->probe_rt, i) - }); - } + { + psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR); - /* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */ - if (!e_data.planar_pool_placeholder) { - e_data.planar_pool_placeholder = DRW_texture_create_2D_array(1, 1, 1, GPU_RGBA8, DRW_TEX_FILTER, NULL); - } + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute); + DRW_shgroup_uniform_int(grp, "outputSize", &pinfo->shres, 1); + DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1); + DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1); + DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1); + DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1); + DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1); + DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); + DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth); - if (!e_data.depth_placeholder) { - e_data.depth_placeholder = DRW_texture_create_2D(1, 1, GPU_DEPTH_COMPONENT24, 0, NULL); + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call_add(grp, geom, NULL); } - if (!e_data.depth_array_placeholder) { - e_data.depth_array_placeholder = DRW_texture_create_2D_array(1, 1, 1, GPU_DEPTH_COMPONENT24, 0, 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_texture_ref(grp, "irradianceGrid", &light_cache->grid_tx.tex); + + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); + DRW_shgroup_call_add(grp, geom, NULL); } } @@ -391,26 +435,21 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; + LightCache *lcache = stl->g_data->light_cache; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - /* Make sure no aditionnal visibility check runs by default. */ + pinfo->num_planar = 0; pinfo->vis_data.collection = NULL; - + pinfo->do_grid_update = false; pinfo->do_cube_update = false; - pinfo->num_cube = 1; /* at least one for the world */ - pinfo->num_grid = 1; - pinfo->num_planar = 0; - pinfo->total_irradiance_samples = 1; - memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref)); - memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref)); - memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref)); { psl->probe_background = DRW_pass_create("World Probe Background Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); - struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); + struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = NULL; - const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; World *wo = scene->world; @@ -421,11 +460,9 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat /* END */ if (!grp && wo) { col = &wo->horr; - bool wo_sh_compiled = true; if (wo->use_nodes && wo->nodetree) { 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_world_lightprobe_get(scene, wo); GPUMaterialStatus status = GPU_material_status(gpumat); @@ -435,35 +472,12 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat grp = DRW_shgroup_material_create(gpumat, psl->probe_background); DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); DRW_shgroup_call_add(grp, geom, NULL); - wo_sh_compiled = true; break; - case GPU_MAT_QUEUED: - pinfo->all_materials_updated = false; - wo_sh_compiled = false; - /* TODO Bypass probe compilation. */ - col = compile_col; - break; - case GPU_MAT_FAILED: default: - wo_sh_compiled = true; col = error_col; break; } } - - if (wo->update_flag != 0 || pinfo->prev_world != wo || pinfo->prev_wo_sh_compiled != wo_sh_compiled) { - pinfo->update_world |= PROBE_UPDATE_ALL; - pinfo->studiolight_index = 0; - pinfo->prev_wo_sh_compiled = wo_sh_compiled; - pinfo->prev_world = wo; - } - wo->update_flag = 0; - } - else if (pinfo->prev_world) { - pinfo->update_world |= PROBE_UPDATE_ALL; - pinfo->studiolight_index = 0; - pinfo->prev_wo_sh_compiled = false; - pinfo->prev_world = NULL; } /* Fallback if shader fails or if not using nodetree. */ @@ -475,99 +489,48 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat } } - { - psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute); - DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1); - DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); - DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); - DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1); - DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1); - DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); - // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); - DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - psl->probe_diffuse_compute = DRW_pass_create("LightProbe Diffuse Compute", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute); -#ifdef IRRADIANCE_SH_L2 - DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1); -#else - DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); - DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); - DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); -#endif - DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); - DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); - - struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); - } - - { - 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", &pinfo->shres, 1); - DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1); - DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1); - DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1); - DRW_shgroup_uniform_float(grp, "farClip", &pinfo->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_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool); - - struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); - } - - { + if (DRW_state_draw_support()) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; psl->probe_display = DRW_pass_create("LightProbe Display", state); - DRW_shgroup_instance_format(e_data.format_probe_display_cube, { - {"probe_id", DRW_ATTRIB_INT, 1}, - {"probe_location", DRW_ATTRIB_FLOAT, 3}, - {"sphere_size", DRW_ATTRIB_FLOAT, 1}, - }); + /* Cube Display */ + if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_CUBEMAPS && lcache->cube_len > 1) { + int cube_len = lcache->cube_len - 1; /* don't count the world. */ + DRWShadingGroup *grp = DRW_shgroup_empty_tri_batch_create(e_data.probe_cube_display_sh, + psl->probe_display, cube_len * 2); + DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_uniform_float_copy(grp, "sphere_size", scene_eval->eevee.gi_cubemap_draw_size * 0.5f); + } - DRWShadingGroup *grp = DRW_shgroup_instance_create( - e_data.probe_cube_display_sh, - psl->probe_display, - DRW_cache_sphere_get(), - e_data.format_probe_display_cube); - stl->g_data->cube_display_shgrp = grp; - DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &sldata->probe_pool); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + /* Grid Display */ + if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_IRRADIANCE) { + EEVEE_LightGrid *egrid = lcache->grid_data + 1; + for (int p = 1; p < lcache->grid_len; ++p, egrid++) { + DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.probe_grid_display_sh, psl->probe_display); + DRW_shgroup_uniform_int(shgrp, "offset", &egrid->offset, 1); + DRW_shgroup_uniform_ivec3(shgrp, "grid_resolution", egrid->resolution, 1); + DRW_shgroup_uniform_vec3(shgrp, "corner", egrid->corner, 1); + DRW_shgroup_uniform_vec3(shgrp, "increment_x", egrid->increment_x, 1); + DRW_shgroup_uniform_vec3(shgrp, "increment_y", egrid->increment_y, 1); + DRW_shgroup_uniform_vec3(shgrp, "increment_z", egrid->increment_z, 1); + DRW_shgroup_uniform_vec3(shgrp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); + DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex); + DRW_shgroup_uniform_float_copy(shgrp, "sphere_size", scene_eval->eevee.gi_irradiance_draw_size * 0.5f); + int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2; + DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, NULL); + } + } + /* Planar Display */ DRW_shgroup_instance_format(e_data.format_probe_display_planar, { {"probe_id", DRW_ATTRIB_INT, 1}, {"probe_mat", DRW_ATTRIB_FLOAT, 16}, }); - grp = DRW_shgroup_instance_create( + DRWShadingGroup *grp = DRW_shgroup_instance_create( e_data.probe_planar_display_sh, psl->probe_display, DRW_cache_quad_get(), @@ -575,6 +538,9 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat stl->g_data->planar_display_shgrp = grp; DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool); } + else { + stl->g_data->planar_display_shgrp = NULL; + } { psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR); @@ -586,809 +552,484 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat } } -bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data) +static bool eevee_lightprobes_culling_test(Object *ob) { - EEVEE_ObjectEngineData *oed = (EEVEE_ObjectEngineData *)user_data; - - /* test disabled if group is NULL */ - if (oed->test_data->collection == NULL) - return vis_in; - - if (oed->test_data->cached == false) - oed->ob_vis_dirty = true; - - /* early out, don't need to compute ob_vis yet. */ - if (vis_in == false) - return vis_in; + LightProbe *probe = (LightProbe *)ob->data; - if (oed->ob_vis_dirty) { - oed->ob_vis_dirty = false; - oed->ob_vis = BKE_collection_has_object_recursive(oed->test_data->collection, oed->ob); - oed->ob_vis = (oed->test_data->invert) ? !oed->ob_vis : oed->ob_vis; + switch (probe->type) { + case LIGHTPROBE_TYPE_PLANAR: + { + /* See if this planar probe is inside the view frustum. If not, no need to update it. */ + /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */ + BoundBox bbox; float tmp[4][4]; + const float min[3] = {-1.0f, -1.0f, -1.0f}; + const float max[3] = { 1.0f, 1.0f, 1.0f}; + BKE_boundbox_init_from_minmax(&bbox, min, max); + + copy_m4_m4(tmp, ob->obmat); + normalize_v3(tmp[2]); + mul_v3_fl(tmp[2], probe->distinf); + + for (int v = 0; v < 8; ++v) { + mul_m4_v3(tmp, bbox.vec[v]); + } + return DRW_culling_box_test(&bbox); + } + case LIGHTPROBE_TYPE_CUBE: + return true; /* TODO */ + case LIGHTPROBE_TYPE_GRID: + return true; /* TODO */ } - - return vis_in && oed->ob_vis; + BLI_assert(0); + return true; } -void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) +void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob) { EEVEE_LightProbesInfo *pinfo = sldata->probes; LightProbe *probe = (LightProbe *)ob->data; if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) || (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) || - (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_grid >= MAX_PLANAR)) + (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR)) { - printf("Too much probes in the scene !!!\n"); + printf("Too many probes in the view !!!\n"); return; } if (probe->type == LIGHTPROBE_TYPE_PLANAR) { - /* See if this planar probe is inside the view frustum. If not, no need to update it. */ - /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */ - BoundBox bbox; float tmp[4][4]; - const float min[3] = {-1.0f, -1.0f, -1.0f}; - const float max[3] = { 1.0f, 1.0f, 1.0f}; - BKE_boundbox_init_from_minmax(&bbox, min, max); - - copy_m4_m4(tmp, ob->obmat); - normalize_v3(tmp[2]); - mul_v3_fl(tmp[2], probe->distinf); - - for (int v = 0; v < 8; ++v) { - mul_m4_v3(tmp, bbox.vec[v]); - } - if (!DRW_culling_box_test(&bbox)) { + if (!eevee_lightprobes_culling_test(ob)) { return; /* Culled */ } - } - - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - - ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z; - - if ((probe->type == LIGHTPROBE_TYPE_GRID) && - ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES)) - { - printf("Too much grid samples !!!\n"); - return; - } - - if (ped->need_full_update) { - ped->need_full_update = false; - - ped->need_update = true; - ped->probe_id = 0; - if (probe->type == LIGHTPROBE_TYPE_GRID) { - ped->updated_cells = 0; - ped->updated_lvl = 0; - pinfo->updated_bounce = 0; - pinfo->grid_initialized = false; + EEVEE_lightprobes_planar_data_from_object(ob, + &pinfo->planar_data[pinfo->num_planar], + &pinfo->planar_vis_tests[pinfo->num_planar]); + /* Debug Display */ + DRWShadingGroup *grp = vedata->stl->g_data->planar_display_shgrp; + if (grp && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { + DRW_shgroup_call_dynamic_add(grp, &pinfo->num_planar, ob->obmat); } - } - if (pinfo->update_world) { - ped->need_update = true; - ped->updated_cells = 0; - ped->updated_lvl = 0; - ped->probe_id = 0; + pinfo->num_planar++; } - - pinfo->do_cube_update |= ped->need_update; - - switch (probe->type) { - case LIGHTPROBE_TYPE_CUBE: - pinfo->probes_cube_ref[pinfo->num_cube] = ob; - pinfo->num_cube++; - break; - case LIGHTPROBE_TYPE_PLANAR: - pinfo->probes_planar_ref[pinfo->num_planar] = ob; - pinfo->num_planar++; - break; - case LIGHTPROBE_TYPE_GRID: - pinfo->probes_grid_ref[pinfo->num_grid] = ob; - pinfo->num_grid++; - pinfo->total_irradiance_samples += ped->num_cell; - break; - } -} - -/* TODO find a nice name to push it to math_matrix.c */ -static void scale_m4_v3(float R[4][4], float v[3]) -{ - for (int i = 0; i < 4; ++i) - mul_v3_v3(R[i], v); -} - -static void EEVEE_planar_reflections_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl) -{ - EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - - for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { - LightProbe *probe = (LightProbe *)ob->data; + else { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - - ped->probe_id = i; - - /* Debug Display */ - if (DRW_state_draw_support() && - (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) - { - DRW_shgroup_call_dynamic_add(stl->g_data->planar_display_shgrp, &ped->probe_id, ob->obmat); + if (ped->need_update) { + if (probe->type == LIGHTPROBE_TYPE_GRID) { + pinfo->do_grid_update = true; + } + else { + pinfo->do_cube_update = true; + } + ped->need_update = false; } } } -static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata) +void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *egrid, int *offset) { - EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4]; - - float viewmat[4][4]; - DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); - - zero_m4(rangemat); - rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f; - rangemat[3][0] = rangemat[3][1] = rangemat[3][2] = 0.5f; - rangemat[3][3] = 1.0f; + LightProbe *probe = (LightProbe *)ob->data; - /* PLANAR REFLECTION */ - for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { - LightProbe *probe = (LightProbe *)ob->data; - EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i]; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - /* Computing mtx : matrix that mirror position around object's XY plane. */ - normalize_m4_m4(normat, ob->obmat); /* object > world */ - invert_m4_m4(imat, normat); /* world > object */ - float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */ - scale_m4_v3(imat, reflect); /* world > object > mirrored obj */ - mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */ - /* Reflect Camera Matrix. */ - mul_m4_m4m4(ped->mats.mat[DRW_MAT_VIEW], viewmat, mtx); - /* TODO FOV margin */ - /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */ - DRW_viewport_matrix_get(ped->mats.mat[DRW_MAT_WIN], DRW_MAT_WIN); - /* Apply Projection Matrix. */ - mul_m4_m4m4(ped->mats.mat[DRW_MAT_PERS], ped->mats.mat[DRW_MAT_WIN], ped->mats.mat[DRW_MAT_VIEW]); - /* This is the matrix used to reconstruct texture coordinates. - * We use the original view matrix because it does not create - * visual artifacts if receiver is not perfectly aligned with - * the planar reflection probe. */ - mul_m4_m4m4(eplanar->reflectionmat, ped->mats.mat[DRW_MAT_WIN], viewmat); /* TODO FOV margin */ - /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */ - mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat); - - /* Compute clip plane equation / normal. */ - float refpoint[3]; - copy_v3_v3(eplanar->plane_equation, ob->obmat[2]); - normalize_v3(eplanar->plane_equation); /* plane normal */ - eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]); - - /* Compute offset plane equation (fix missing texels near reflection plane). */ - copy_v3_v3(ped->planer_eq_offset, eplanar->plane_equation); - mul_v3_v3fl(refpoint, eplanar->plane_equation, -probe->clipsta); - add_v3_v3(refpoint, ob->obmat[3]); - ped->planer_eq_offset[3] = -dot_v3v3(eplanar->plane_equation, refpoint); - - /* Compute XY clip planes. */ - normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]); - normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]); - - float vec[3] = {0.0f, 0.0f, 0.0f}; - vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ - eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec); - - vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ - eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec); - - vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ - eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec); - - vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f; - mul_m4_v3(ob->obmat, vec); /* Point on the edge */ - eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec); - - /* Facing factors */ - float max_angle = max_ff(1e-2f, probe->falloff) * M_PI * 0.5f; - float min_angle = 0.0f; - eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle)); - eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale; - - /* Distance factors */ - float max_dist = probe->distinf; - float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf; - eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist); - eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale; - } + copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x); + + /* Save current offset and advance it for the next grid. */ + egrid->offset = *offset; + *offset += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2]; + + /* Add one for level 0 */ + float fac = 1.0f / max_ff(1e-8f, probe->falloff); + egrid->attenuation_scale = fac / max_ff(1e-8f, probe->distinf); + egrid->attenuation_bias = fac; + + /* Update transforms */ + float cell_dim[3], half_cell_dim[3]; + cell_dim[0] = 2.0f / egrid->resolution[0]; + cell_dim[1] = 2.0f / egrid->resolution[1]; + cell_dim[2] = 2.0f / egrid->resolution[2]; + + mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f); + + /* Matrix converting world space to cell ranges. */ + invert_m4_m4(egrid->mat, ob->obmat); + + /* First cell. */ + copy_v3_fl(egrid->corner, -1.0f); + add_v3_v3(egrid->corner, half_cell_dim); + mul_m4_v3(ob->obmat, egrid->corner); + + /* Opposite neighbor cell. */ + copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f); + add_v3_v3(egrid->increment_x, half_cell_dim); + add_v3_fl(egrid->increment_x, -1.0f); + mul_m4_v3(ob->obmat, egrid->increment_x); + sub_v3_v3(egrid->increment_x, egrid->corner); + + copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f); + add_v3_v3(egrid->increment_y, half_cell_dim); + add_v3_fl(egrid->increment_y, -1.0f); + mul_m4_v3(ob->obmat, egrid->increment_y); + sub_v3_v3(egrid->increment_y, egrid->corner); + + copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]); + add_v3_v3(egrid->increment_z, half_cell_dim); + add_v3_fl(egrid->increment_z, -1.0f); + mul_m4_v3(ob->obmat, egrid->increment_z); + sub_v3_v3(egrid->increment_z, egrid->corner); + + /* Visibility bias */ + egrid->visibility_bias = 0.05f * probe->vis_bias; + egrid->visibility_bleed = probe->vis_bleedbias; + egrid->visibility_range = 1.0f + sqrtf(max_fff(len_squared_v3(egrid->increment_x), + len_squared_v3(egrid->increment_y), + len_squared_v3(egrid->increment_z))); } -static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl) +void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprobe) { - EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - - /* CUBE REFLECTION */ - for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { - LightProbe *probe = (LightProbe *)ob->data; - EEVEE_LightProbe *eprobe = &pinfo->probe_data[i]; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + LightProbe *probe = (LightProbe *)ob->data; - /* Update transforms */ - copy_v3_v3(eprobe->position, ob->obmat[3]); + /* Update transforms */ + copy_v3_v3(eprobe->position, ob->obmat[3]); - /* Attenuation */ - eprobe->attenuation_type = probe->attenuation_type; - eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff); + /* Attenuation */ + eprobe->attenuation_type = probe->attenuation_type; + eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff); - unit_m4(eprobe->attenuationmat); - scale_m4_fl(eprobe->attenuationmat, probe->distinf); - mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat); - invert_m4(eprobe->attenuationmat); + unit_m4(eprobe->attenuationmat); + scale_m4_fl(eprobe->attenuationmat, probe->distinf); + mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat); + invert_m4(eprobe->attenuationmat); - /* Parallax */ - float dist; - if ((probe->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) { - eprobe->parallax_type = probe->parallax_type; - dist = probe->distpar; - } - else { - eprobe->parallax_type = probe->attenuation_type; - dist = probe->distinf; - } + /* Parallax */ + unit_m4(eprobe->parallaxmat); - unit_m4(eprobe->parallaxmat); - scale_m4_fl(eprobe->parallaxmat, dist); - mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat); - invert_m4(eprobe->parallaxmat); - - /* Debug Display */ - if (DRW_state_draw_support() && - (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) - { - ped->probe_size = probe->data_draw_size * 0.1f; - DRW_shgroup_call_dynamic_add( - stl->g_data->cube_display_shgrp, &ped->probe_id, ob->obmat[3], &ped->probe_size); - } + if ((probe->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) { + eprobe->parallax_type = probe->parallax_type; + scale_m4_fl(eprobe->parallaxmat, probe->distpar); + } + else { + eprobe->parallax_type = probe->attenuation_type; + scale_m4_fl(eprobe->parallaxmat, probe->distinf); } - /* IRRADIANCE GRID */ - int offset = 1; /* to account for the world probe */ - for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { - LightProbe *probe = (LightProbe *)ob->data; - EEVEE_LightGrid *egrid = &pinfo->grid_data[i]; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat); + invert_m4(eprobe->parallaxmat); +} - /* If one grid has move we need to recompute all the lighting. */ - if (!pinfo->grid_initialized) { - ped->updated_cells = 0; - ped->updated_lvl = 0; - ped->need_update = true; - } +void EEVEE_lightprobes_planar_data_from_object(Object *ob, EEVEE_PlanarReflection *eplanar, EEVEE_LightProbeVisTest *vis_test) +{ + LightProbe *probe = (LightProbe *)ob->data; + float normat[4][4], imat[4][4]; + + vis_test->collection = probe->visibility_grp; + vis_test->invert = probe->flag & LIGHTPROBE_FLAG_INVERT_GROUP; + vis_test->cached = false; + + /* Computing mtx : matrix that mirror position around object's XY plane. */ + normalize_m4_m4(normat, ob->obmat); /* object > world */ + invert_m4_m4(imat, normat); /* world > object */ + /* XY reflection plane */ + imat[0][2] = -imat[0][2]; + imat[1][2] = -imat[1][2]; + imat[2][2] = -imat[2][2]; + imat[3][2] = -imat[3][2]; /* world > object > mirrored obj */ + mul_m4_m4m4(eplanar->mtx, normat, imat); /* world > object > mirrored obj > world */ + + /* Compute clip plane equation / normal. */ + copy_v3_v3(eplanar->plane_equation, ob->obmat[2]); + normalize_v3(eplanar->plane_equation); /* plane normal */ + eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]); + eplanar->clipsta = probe->clipsta; + + /* Compute XY clip planes. */ + normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]); + normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]); + + float vec[3] = {0.0f, 0.0f, 0.0f}; + vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f; + mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec); + + vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f; + mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec); + + vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f; + mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec); + + vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f; + mul_m4_v3(ob->obmat, vec); /* Point on the edge */ + eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec); + + /* Facing factors */ + float max_angle = max_ff(1e-2f, probe->falloff) * M_PI * 0.5f; + float min_angle = 0.0f; + eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle)); + eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale; + + /* Distance factors */ + float max_dist = probe->distinf; + float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf; + eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist); + eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale; +} - /* Add one for level 0 */ - ped->max_lvl = 1.0f + floorf(log2f((float)MAX3(probe->grid_resolution_x, - probe->grid_resolution_y, - probe->grid_resolution_z))); - - egrid->offset = offset; - float fac = 1.0f / max_ff(1e-8f, probe->falloff); - egrid->attenuation_scale = fac / max_ff(1e-8f, probe->distinf); - egrid->attenuation_bias = fac; - - /* Set offset for the next grid */ - offset += ped->num_cell; - - /* Update transforms */ - float cell_dim[3], half_cell_dim[3]; - cell_dim[0] = 2.0f / (float)(probe->grid_resolution_x); - cell_dim[1] = 2.0f / (float)(probe->grid_resolution_y); - cell_dim[2] = 2.0f / (float)(probe->grid_resolution_z); - - mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f); - - /* Matrix converting world space to cell ranges. */ - invert_m4_m4(egrid->mat, ob->obmat); - - /* First cell. */ - copy_v3_fl(egrid->corner, -1.0f); - add_v3_v3(egrid->corner, half_cell_dim); - mul_m4_v3(ob->obmat, egrid->corner); - - /* Opposite neighbor cell. */ - copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f); - add_v3_v3(egrid->increment_x, half_cell_dim); - add_v3_fl(egrid->increment_x, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_x); - sub_v3_v3(egrid->increment_x, egrid->corner); - - copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f); - add_v3_v3(egrid->increment_y, half_cell_dim); - add_v3_fl(egrid->increment_y, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_y); - sub_v3_v3(egrid->increment_y, egrid->corner); - - copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]); - add_v3_v3(egrid->increment_z, half_cell_dim); - add_v3_fl(egrid->increment_z, -1.0f); - mul_m4_v3(ob->obmat, egrid->increment_z); - sub_v3_v3(egrid->increment_z, egrid->corner); - - 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 = ( - sqrtf(max_fff(len_squared_v3(egrid->increment_x), - len_squared_v3(egrid->increment_y), - len_squared_v3(egrid->increment_z))) + 1.0f); +static void lightbake_planar_compute_render_matrices( + EEVEE_PlanarReflection *eplanar, DRWMatrixState *r_matstate, const float viewmat[4][4]) +{ + /* Reflect Camera Matrix. */ + mul_m4_m4m4(r_matstate->viewmat, viewmat, eplanar->mtx); + /* TODO FOV margin */ + /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */ + DRW_viewport_matrix_get(r_matstate->winmat, DRW_MAT_WIN); + /* Apply Projection Matrix. */ + mul_m4_m4m4(r_matstate->persmat, r_matstate->winmat, r_matstate->viewmat); + + /* This is the matrix used to reconstruct texture coordinates. + * We use the original view matrix because it does not create + * visual artifacts if receiver is not perfectly aligned with + * the planar reflection probe. */ + mul_m4_m4m4(eplanar->reflectionmat, r_matstate->winmat, viewmat); /* TODO FOV margin */ + /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */ + mul_m4_m4m4(eplanar->reflectionmat, texcomat, eplanar->reflectionmat); +} - /* Debug Display */ - if (DRW_state_draw_support() && - (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) - { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_display_sh, psl->probe_display); - DRW_shgroup_uniform_int(grp, "offset", &egrid->offset, 1); - DRW_shgroup_uniform_ivec3(grp, "grid_resolution", egrid->resolution, 1); - DRW_shgroup_uniform_vec3(grp, "corner", egrid->corner, 1); - DRW_shgroup_uniform_vec3(grp, "increment_x", egrid->increment_x, 1); - DRW_shgroup_uniform_vec3(grp, "increment_y", egrid->increment_y, 1); - DRW_shgroup_uniform_vec3(grp, "increment_z", egrid->increment_z, 1); - DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool); - DRW_shgroup_uniform_float(grp, "sphere_size", &probe->data_draw_size, 1); - DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, (uint *)&ped->num_cell); - } - } +static void eevee_lightprobes_extract_from_cache(EEVEE_LightProbesInfo *pinfo, LightCache *lcache) +{ + /* copy the entire cache for now (up to MAX_PROBE) */ + /* TODO Frutum cull to only add visible probes. */ + memcpy(pinfo->probe_data, lcache->cube_data, sizeof(EEVEE_LightProbe) * max_ii(1, min_ii(lcache->cube_len, MAX_PROBE))); + /* TODO compute the max number of grid based on sample count. */ + memcpy(pinfo->grid_data, lcache->grid_data, sizeof(EEVEE_LightGrid) * max_ii(1, min_ii(lcache->grid_len, MAX_GRID))); } void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_StorageList *stl = vedata->stl; + LightCache *light_cache = stl->g_data->light_cache; EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - /* Setup enough layers. */ - /* Free textures if number mismatch. */ - if (pinfo->num_cube != pinfo->cache_num_cube) { - DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); - pinfo->cache_num_cube = pinfo->num_cube; - } + eevee_lightprobes_extract_from_cache(sldata->probes, light_cache); + + DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data); + DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); + + /* For shading, save max level of the octahedron map */ + sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len - 1.0f; + sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL; + sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res; + sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len); + sldata->common_data.prb_num_render_grid = max_ii(1, light_cache->grid_len); + sldata->common_data.prb_num_planar = pinfo->num_planar; if (pinfo->num_planar != pinfo->cache_num_planar) { DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool); DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_depth); pinfo->cache_num_planar = pinfo->num_planar; } - - int irr_size[3]; - irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, irr_size); - - if ((irr_size[0] != pinfo->cache_irradiance_size[0]) || - (irr_size[1] != pinfo->cache_irradiance_size[1]) || - (irr_size[2] != pinfo->cache_irradiance_size[2])) - { - DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); - DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); - copy_v3_v3_int(pinfo->cache_irradiance_size, irr_size); - } - - /* XXX this should be run each frame as it ensure planar_depth is set */ planar_pool_ensure_alloc(vedata, pinfo->num_planar); - if (!sldata->probe_pool) { - sldata->probe_pool = DRW_texture_create_2D_array(pinfo->cubemap_res, pinfo->cubemap_res, max_ff(1, pinfo->num_cube), - GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); - if (sldata->probe_filter_fb) { - GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); - } - /* Tag probes to refresh */ - pinfo->update_world |= PROBE_UPDATE_CUBE; - } + /* If lightcache auto-update is enable we tag the relevant part + * of the cache to update and fire up a baking job. */ + if (!DRW_state_is_image_render() && !DRW_state_is_opengl_render() && + (pinfo->do_grid_update || pinfo->do_cube_update)) + { + const DRWContextState *draw_ctx = DRW_context_state_get(); + BLI_assert(draw_ctx->evil_C); - if ((pinfo->update_world & PROBE_UPDATE_CUBE) != 0) { - common_data->prb_num_render_cube = 0; - for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - ped->need_update = true; - ped->ready_to_shade = false; - ped->probe_id = 0; + if (draw_ctx->scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) { + Scene *scene_orig = DEG_get_input_scene(draw_ctx->depsgraph); + if (scene_orig->eevee.light_cache != NULL) { + if (pinfo->do_grid_update) { + scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID; + } + /* If we update grid we need to update the cubemaps too. + * So always refresh cubemaps. */ + scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; + /* Tag the lightcache to auto update. */ + scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_AUTO; + /* Use a notifier to trigger the operator after drawing. */ + WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig); + } } } +} -#ifdef IRRADIANCE_SH_L2 - /* we need a signed format for Spherical Harmonics */ - int irradiance_format = GPU_RGBA16F; -#else - int irradiance_format = GPU_RGBA8; -#endif +/* -------------------------------------------------------------------- */ - if (!sldata->irradiance_pool || !sldata->irradiance_rt) { - if (!sldata->irradiance_pool) { - sldata->irradiance_pool = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], - irradiance_format, DRW_TEX_FILTER, NULL); - } - if (!sldata->irradiance_rt) { - sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], - irradiance_format, DRW_TEX_FILTER, NULL); - } - /* Tag probes to refresh */ - pinfo->update_world |= PROBE_UPDATE_GRID; - pinfo->grid_initialized = false; - } +/** \name Rendering + * \{ */ - if ((pinfo->update_world & PROBE_UPDATE_GRID) != 0) { - common_data->prb_num_render_grid = 0; - pinfo->updated_bounce = 0; - for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - ped->need_update = true; - ped->updated_cells = 0; - } - } +typedef struct EEVEE_BakeRenderData { + EEVEE_Data *vedata; + EEVEE_ViewLayerData *sldata; + struct GPUFrameBuffer **face_fb; /* should contain 6 framebuffer */ +} EEVEE_BakeRenderData; - if (common_data->prb_num_render_grid > pinfo->num_grid) { - /* This can happen when deleting a probe. */ - common_data->prb_num_render_grid = pinfo->num_grid; - } +static void render_cubemap( + void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data, + const float pos[3], float clipsta, float clipend) +{ + DRWMatrixState matstate; - EEVEE_planar_reflections_cache_finish(sldata, vedata->stl); + /* Move to capture position */ + float posmat[4][4]; + unit_m4(posmat); + negate_v3_v3(posmat[3], pos); - EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl); + perspective_m4(matstate.winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend); + invert_m4_m4(matstate.wininv, matstate.winmat); - DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data); - DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); -} + /* 1 - Render to each cubeface individually. + * We do this instead of using geometry shader because a) it's faster, + * b) it's easier than fixing the nodetree shaders (for view dependant effects). */ + for (int i = 0; i < 6; ++i) { + /* Setup custom matrices */ + mul_m4_m4m4(matstate.viewmat, cubefacemat[i], posmat); + mul_m4_m4m4(matstate.persmat, matstate.winmat, matstate.viewmat); + invert_m4_m4(matstate.persinv, matstate.persmat); + invert_m4_m4(matstate.viewinv, matstate.viewmat); + invert_m4_m4(matstate.wininv, matstate.winmat); -static void downsample_planar(void *vedata, int level) -{ - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + DRW_viewport_matrix_override_set_all(&matstate); - const float *size = DRW_viewport_size_get(); - copy_v2_v2(stl->g_data->planar_texel_size, size); - for (int i = 0; i < level - 1; ++i) { - stl->g_data->planar_texel_size[0] /= 2.0f; - stl->g_data->planar_texel_size[1] /= 2.0f; - min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f); - min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f); + callback(i, user_data); } - invert_v2(stl->g_data->planar_texel_size); - - DRW_draw_pass(psl->probe_planar_downsample_ps); } -/* Glossy filter probe_rt to probe_pool at index probe_idx */ -static void glossy_filter_probe( - EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx, float intensity) +static void render_reflections( + void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data, + EEVEE_PlanarReflection *planar_data, int ref_count) { - EEVEE_LightProbesInfo *pinfo = sldata->probes; - - pinfo->intensity_fac = intensity; - - /* Max lod used from the render target probe */ - pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f; - - /* Start fresh */ - GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_NONE - }); - - /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */ - /* Bind next framebuffer to be able to gen. mips for probe_rt. */ - EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max)); - - /* 3 - Render to probe array to the specified layer, do prefiltering. */ - float mipsize = pinfo->cubemap_res; - const int maxlevel = (int)floorf(log2f(pinfo->cubemap_res)); - const int min_lod_level = 3; - for (int i = 0; i < maxlevel - min_lod_level; i++) { - float bias = (i == 0) ? -1.0f : 1.0f; - pinfo->texel_size = 1.0f / mipsize; - pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i)); - /* XXX : WHY THE HECK DO WE NEED THIS ??? */ - /* padding is incorrect without this! float precision issue? */ - if (pinfo->padding_size > 32) { - pinfo->padding_size += 5; - } - if (pinfo->padding_size > 16) { - pinfo->padding_size += 4; - } - else if (pinfo->padding_size > 8) { - pinfo->padding_size += 2; - } - else if (pinfo->padding_size > 4) { - pinfo->padding_size += 1; - } - pinfo->layer = probe_idx; - pinfo->roughness = (float)i / ((float)maxlevel - 4.0f); - pinfo->roughness *= pinfo->roughness; /* Disney Roughness */ - pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */ - CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */ - -#if 1 /* Variable Sample count (fast) */ - switch (i) { - case 0: pinfo->samples_ct = 1.0f; break; - case 1: pinfo->samples_ct = 16.0f; break; - case 2: pinfo->samples_ct = 32.0f; break; - case 3: pinfo->samples_ct = 64.0f; break; - default: pinfo->samples_ct = 128.0f; break; - } -#else /* Constant Sample count (slow) */ - pinfo->samples_ct = 1024.0f; -#endif + DRWMatrixState matstate; - pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; - pinfo->lodfactor = bias + 0.5f * log((float)(pinfo->target_size * pinfo->target_size) * pinfo->invsamples_ct) / log(2); + float original_viewmat[4][4]; + DRW_viewport_matrix_get(original_viewmat, DRW_MAT_VIEW); - GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE_MIP(sldata->probe_pool, i) - }); - GPU_framebuffer_bind(sldata->probe_filter_fb); - GPU_framebuffer_viewport_set(sldata->probe_filter_fb, 0, 0, mipsize, mipsize); - DRW_draw_pass(psl->probe_glossy_compute); + for (int i = 0; i < ref_count; ++i) { + /* Setup custom matrices */ + lightbake_planar_compute_render_matrices(planar_data + i, &matstate, original_viewmat); + invert_m4_m4(matstate.persinv, matstate.persmat); + invert_m4_m4(matstate.viewinv, matstate.viewmat); + invert_m4_m4(matstate.wininv, matstate.winmat); + DRW_viewport_matrix_override_set_all(&matstate); - mipsize /= 2; - CLAMP_MIN(mipsize, 1); + callback(i, user_data); } - /* For shading, save max level of the octahedron map */ - sldata->common_data.prb_lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f; } -/* 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, - float clipsta, float clipend, float vis_range, float vis_blur, float intensity) +static void lightbake_render_world_face(int face, EEVEE_BakeRenderData *user_data) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_LightProbesInfo *pinfo = sldata->probes; + EEVEE_PassList *psl = user_data->vedata->psl; + struct GPUFrameBuffer **face_fb = user_data->face_fb; - pinfo->intensity_fac = intensity; + /* For world probe, we don't need to clear the color buffer + * since we render the background directly. */ + GPU_framebuffer_bind(face_fb[face]); + GPU_framebuffer_clear_depth(face_fb[face], 1.0f); + DRW_draw_pass(psl->probe_background); +} - int pool_size[3]; - irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, pool_size); +void EEVEE_lightbake_render_world(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6]) +{ + EEVEE_BakeRenderData brdata = { + .vedata = vedata, + .face_fb = face_fb + }; - /* find cell position on the virtual 3D texture */ - /* NOTE : Keep in sync with load_irradiance_cell() */ -#if defined(IRRADIANCE_SH_L2) - int size[2] = {3, 3}; -#elif defined(IRRADIANCE_CUBEMAP) - int size[2] = {8, 8}; - pinfo->samples_ct = 1024.0f; -#elif defined(IRRADIANCE_HL2) - int size[2] = {3, 2}; - pinfo->samples_ct = 1024.0f; -#endif + render_cubemap(lightbake_render_world_face, &brdata, (float[3]){0.0f}, 1.0f, 10.0f); +} - int cell_per_row = pool_size[0] / size[0]; - int x = size[0] * (offset % cell_per_row); - int y = size[1] * (offset / cell_per_row); +static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_data) +{ + EEVEE_ViewLayerData *sldata = user_data->sldata; + EEVEE_PassList *psl = user_data->vedata->psl; + struct GPUFrameBuffer **face_fb = user_data->face_fb; -#ifndef IRRADIANCE_SH_L2 - /* Tweaking parameters to balance perf. vs precision */ - const float bias = 0.0f; - pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; - pinfo->lodfactor = bias + 0.5f * log((float)(pinfo->target_size * pinfo->target_size) * pinfo->invsamples_ct) / log(2); - pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f; -#else - pinfo->shres = 32; /* Less texture fetches & reduce branches */ - pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */ -#endif + /* Be sure that cascaded shadow maps are updated. */ + EEVEE_draw_shadows(sldata, psl); - /* Start fresh */ - GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_NONE - }); + GPU_framebuffer_bind(face_fb[face]); + GPU_framebuffer_clear_depth(face_fb[face], 1.0f); - /* 4 - Compute spherical harmonics */ - EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max)); + 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->sss_pass); /* Only output standard pass */ + EEVEE_draw_default_passes(psl); +} - GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, 0) - }); - GPU_framebuffer_bind(sldata->probe_filter_fb); - GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, size[0], size[1]); - DRW_draw_pass(psl->probe_diffuse_compute); +/* Render the scene to the probe_rt texture. */ +void EEVEE_lightbake_render_scene( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6], + const float pos[3], float near_clip, float far_clip) +{ + EEVEE_BakeRenderData brdata = { + .vedata = vedata, + .sldata = sldata, + .face_fb = face_fb + }; - /* World irradiance have no visibility */ - if (offset > 0) { - /* Compute visibility */ - pinfo->samples_ct = 512.0f; /* TODO refine */ - pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; - pinfo->shres = common_data->prb_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)common_data->prb_irradiance_vis_size; - - int cell_per_col = pool_size[1] / common_data->prb_irradiance_vis_size; - cell_per_row = pool_size[0] / common_data->prb_irradiance_vis_size; - x = common_data->prb_irradiance_vis_size * (offset % cell_per_row); - y = common_data->prb_irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); - int layer = 1 + ((offset / cell_per_row) / cell_per_col); - const int vis_size = common_data->prb_irradiance_vis_size; - - GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, layer) - }); - GPU_framebuffer_bind(sldata->probe_filter_fb); - GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, vis_size, vis_size); - DRW_draw_pass(psl->probe_visibility_compute); - } + render_cubemap(lightbake_render_scene_face, &brdata, pos, near_clip, far_clip); } -/* Render the scene to the probe_rt texture. */ -static void render_scene_to_probe( - EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - const float pos[3], float clipsta, float clipend) +static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *user_data) { - EEVEE_TextureList *txl = vedata->txl; + EEVEE_Data *vedata = user_data->vedata; + EEVEE_ViewLayerData *sldata = user_data->sldata; EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_LightProbesInfo *pinfo = sldata->probes; + EEVEE_PlanarReflection *eplanar = pinfo->planar_data + layer; - DRWMatrixState matstate; - float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW]; - float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV]; - float (*persmat)[4] = matstate.mat[DRW_MAT_PERS]; - float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV]; - float (*winmat)[4] = matstate.mat[DRW_MAT_WIN]; - float (*wininv)[4] = matstate.mat[DRW_MAT_WININV]; - - float posmat[4][4]; - unit_m4(posmat); - - /* Move to capture position */ - negate_v3_v3(posmat[3], pos); + GPU_framebuffer_ensure_config(&fbl->planarref_fb, { + GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer), + GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer) + }); - /* 1 - Render to each cubeface individually. - * We do this instead of using geometry shader because a) it's faster, - * b) it's easier than fixing the nodetree shaders (for view dependant effects). */ - pinfo->layer = 0; - perspective_m4(winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend); + /* Use visibility info for this planar reflection. */ + pinfo->vis_data = pinfo->planar_vis_tests[layer]; /* Avoid using the texture attached to framebuffer when rendering. */ /* XXX */ GPUTexture *tmp_planar_pool = txl->planar_pool; - GPUTexture *tmp_maxz = txl->maxzbuffer; + GPUTexture *tmp_planar_depth = txl->planar_depth; txl->planar_pool = e_data.planar_pool_placeholder; - txl->maxzbuffer = e_data.depth_placeholder; - - DRW_stats_group_start("Cubemap Render"); - - /* Update common uniforms */ - DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - - for (int i = 0; i < 6; ++i) { - /* Recompute only on 1st drawloop. */ - pinfo->vis_data.cached = (i != 0); - - DRW_stats_group_start("Cubemap Face"); - - /* Setup custom matrices */ - mul_m4_m4m4(viewmat, cubefacemat[i], posmat); - mul_m4_m4m4(persmat, winmat, viewmat); - invert_m4_m4(persinv, persmat); - invert_m4_m4(viewinv, viewmat); - invert_m4_m4(wininv, winmat); - - DRW_viewport_matrix_override_set_all(&matstate); - - /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, psl); - - GPU_framebuffer_bind(sldata->probe_face_fb[i]); - GPU_framebuffer_clear_depth(sldata->probe_face_fb[i], 1.0); - - /* Depth prepass */ - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); - - DRW_draw_pass(psl->probe_background); - - // EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt); - - /* Rebind Target FB */ - GPU_framebuffer_bind(sldata->probe_face_fb[i]); - - /* Shading pass */ - EEVEE_draw_default_passes(psl); - DRW_draw_pass(psl->material_pass); - DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ - - DRW_stats_group_end(); - } - - DRW_stats_group_end(); - - /* Make sure no aditionnal visibility check runs after this. */ - pinfo->vis_data.collection = NULL; - - /* Restore */ - txl->planar_pool = tmp_planar_pool; - txl->maxzbuffer = tmp_maxz; -} - -static void render_scene_to_planar( - EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int layer, - EEVEE_LightProbeEngineData *ped) -{ - EEVEE_LightProbesInfo *pinfo = sldata->probes; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; - EEVEE_PassList *psl = vedata->psl; - - float (*viewmat)[4] = ped->mats.mat[DRW_MAT_VIEW]; - float (*viewinv)[4] = ped->mats.mat[DRW_MAT_VIEWINV]; - float (*persmat)[4] = ped->mats.mat[DRW_MAT_PERS]; - float (*persinv)[4] = ped->mats.mat[DRW_MAT_PERSINV]; - float (*winmat)[4] = ped->mats.mat[DRW_MAT_WIN]; - float (*wininv)[4] = ped->mats.mat[DRW_MAT_WININV]; - - invert_m4_m4(viewinv, viewmat); - invert_m4_m4(persinv, persmat); - invert_m4_m4(wininv, winmat); + txl->planar_depth = e_data.depth_array_placeholder; + /* Be sure that cascaded shadow maps are updated. */ DRW_stats_group_start("Planar Reflection"); - DRW_viewport_matrix_override_set_all(&ped->mats); - - /* Don't reuse previous visibility. */ - pinfo->vis_data.cached = false; - /* Be sure that cascaded shadow maps are updated. */ EEVEE_draw_shadows(sldata, psl); - /* Since we are rendering with an inverted view matrix, we need * to invert the facing for backface culling to be the same. */ DRW_state_invert_facing(); - /* Set clipping plan */ - copy_v4_v4(sldata->clip_data.clip_planes[0], ped->planer_eq_offset); + /* Compute offset plane equation (fix missing texels near reflection plane). */ + copy_v4_v4(sldata->clip_data.clip_planes[0], eplanar->plane_equation); + sldata->clip_data.clip_planes[0][3] += eplanar->clipsta; + /* Set clipping plane */ DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data); DRW_state_clip_planes_count_set(1); - GPU_framebuffer_ensure_config(&fbl->planarref_fb, { - GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer), - GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer) - }); - GPU_framebuffer_bind(fbl->planarref_fb); GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0); - /* Avoid using the texture attached to framebuffer when rendering. */ - /* XXX */ - GPUTexture *tmp_planar_pool = txl->planar_pool; - GPUTexture *tmp_planar_depth = txl->planar_depth; - txl->planar_pool = e_data.planar_pool_placeholder; - txl->planar_depth = e_data.depth_array_placeholder; - /* Slight modification: we handle refraction as normal * shading and don't do SSRefraction. */ - /* Depth prepass */ DRW_draw_pass(psl->depth_pass_clip); DRW_draw_pass(psl->depth_pass_clip_cull); DRW_draw_pass(psl->refract_depth_pass); DRW_draw_pass(psl->refract_depth_pass_cull); - /* Background */ DRW_draw_pass(psl->probe_background); - EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); - - /* Compute GTAO Horizons */ EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer); - /* Rebind Planar FB */ GPU_framebuffer_bind(fbl->planarref_fb); /* Shading pass */ @@ -1409,134 +1050,229 @@ static void render_scene_to_planar( DRW_stats_group_end(); - /* Make sure no aditionnal visibility check runs after this. */ - pinfo->vis_data.collection = NULL; - /* Restore */ txl->planar_pool = tmp_planar_pool; txl->planar_depth = tmp_planar_depth; } -static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) +static void eevee_lightbake_render_scene_to_planars( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_BakeRenderData brdata = { + .vedata = vedata, + .sldata = sldata, + }; + + render_reflections(lightbake_render_scene_reflected, &brdata, sldata->probes->planar_data, sldata->probes->num_planar); +} +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Filtering + * \{ */ + +/* Glossy filter rt_color to light_cache->cube_tx.tex at index probe_idx */ +void EEVEE_lightbake_filter_glossy( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, + struct GPUTexture *rt_color, struct GPUFrameBuffer *fb, + int probe_idx, float intensity, int maxlevel) { + EEVEE_PassList *psl = vedata->psl; EEVEE_LightProbesInfo *pinfo = sldata->probes; - DRWMatrixState matstate; - float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW]; - float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV]; - float (*persmat)[4] = matstate.mat[DRW_MAT_PERS]; - float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV]; - float (*winmat)[4] = matstate.mat[DRW_MAT_WIN]; - float (*wininv)[4] = matstate.mat[DRW_MAT_WININV]; + LightCache *light_cache = vedata->stl->g_data->light_cache; - /* For world probe, we don't need to clear since we render the background directly. */ - pinfo->layer = 0; + float target_size = (float)GPU_texture_width(rt_color); - perspective_m4(winmat, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f); - invert_m4_m4(wininv, winmat); + /* Max lod used from the render target probe */ + pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f; + pinfo->intensity_fac = intensity; - for (int i = 0; i < 6; ++i) { - /* Setup custom matrices */ - copy_m4_m4(viewmat, cubefacemat[i]); - mul_m4_m4m4(persmat, winmat, viewmat); - invert_m4_m4(persinv, persmat); - invert_m4_m4(viewinv, viewmat); - DRW_viewport_matrix_override_set_all(&matstate); + /* Start fresh */ + GPU_framebuffer_ensure_config(&fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); - GPU_framebuffer_bind(sldata->probe_face_fb[i]); - GPU_framebuffer_clear_depth(sldata->probe_face_fb[i], 1.0f); - DRW_draw_pass(psl->probe_background); - } -} + /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */ + /* Bind next framebuffer to be able to gen. mips for probe_rt. */ + EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max)); -static void lightprobe_cell_grid_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_local_cell[3]) -{ - /* Keep in sync with lightprobe_grid_display_vert */ - r_local_cell[2] = (float)(cell_idx % egrid->resolution[2]); - r_local_cell[1] = (float)((cell_idx / egrid->resolution[2]) % egrid->resolution[1]); - r_local_cell[0] = (float)(cell_idx / (egrid->resolution[2] * egrid->resolution[1])); -} + /* 3 - Render to probe array to the specified layer, do prefiltering. */ + int mipsize = GPU_texture_width(light_cache->cube_tx.tex); + for (int i = 0; i < maxlevel + 1; i++) { + float bias = (i == 0) ? -1.0f : 1.0f; + pinfo->texel_size = 1.0f / (float)mipsize; + pinfo->padding_size = (float)(1 << (maxlevel - i - 1)); + pinfo->padding_size *= pinfo->texel_size; + pinfo->layer = probe_idx; + pinfo->roughness = i / (float)maxlevel; + pinfo->roughness *= pinfo->roughness; /* Disney Roughness */ + pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */ + CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */ -static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float local_cell[3], float r_pos[3]) -{ - float tmp[3]; - - copy_v3_v3(r_pos, egrid->corner); - mul_v3_v3fl(tmp, egrid->increment_x, local_cell[0]); - add_v3_v3(r_pos, tmp); - mul_v3_v3fl(tmp, egrid->increment_y, local_cell[1]); - add_v3_v3(r_pos, tmp); - mul_v3_v3fl(tmp, egrid->increment_z, local_cell[2]); - add_v3_v3(r_pos, tmp); +#if 1 /* Variable Sample count (fast) */ + switch (i) { + case 0: pinfo->samples_len = 1.0f; break; + case 1: pinfo->samples_len = 16.0f; break; + case 2: pinfo->samples_len = 32.0f; break; + case 3: pinfo->samples_len = 64.0f; break; + default: pinfo->samples_len = 128.0f; break; + } +#else /* Constant Sample count (slow) */ + pinfo->samples_len = 1024.0f; +#endif + + pinfo->samples_len_inv = 1.0f / pinfo->samples_len; + pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2); + + GPU_framebuffer_ensure_config(&fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_MIP(light_cache->cube_tx.tex, i) + }); + GPU_framebuffer_bind(fb); + GPU_framebuffer_viewport_set(fb, 0, 0, mipsize, mipsize); + DRW_draw_pass(psl->probe_glossy_compute); + + mipsize /= 2; + CLAMP_MIN(mipsize, 1); + } } -static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +/* Diffuse filter rt_color to light_cache->grid_tx.tex at index grid_offset */ +void EEVEE_lightbake_filter_diffuse( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, + struct GPUTexture *rt_color, struct GPUFrameBuffer *fb, + int grid_offset, float intensity) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_LightProbesInfo *pinfo = sldata->probes; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - DRWMatrixState saved_mats; + EEVEE_LightProbesInfo *pinfo = sldata->probes; + LightCache *light_cache = vedata->stl->g_data->light_cache; - /* We need to save the Matrices before overidding them */ - DRW_viewport_matrix_get_all(&saved_mats); + float target_size = (float)GPU_texture_width(rt_color); - render_world_to_probe(sldata, psl); - if (pinfo->update_world & PROBE_UPDATE_CUBE) { - glossy_filter_probe(sldata, vedata, psl, 0, 1.0); - common_data->prb_num_render_cube = 1; - } - if (pinfo->update_world & PROBE_UPDATE_GRID) { - diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0); + pinfo->intensity_fac = intensity; - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + /* find cell position on the virtual 3D texture */ + /* NOTE : Keep in sync with load_irradiance_cell() */ +#if defined(IRRADIANCE_SH_L2) + int size[2] = {3, 3}; +#elif defined(IRRADIANCE_CUBEMAP) + int size[2] = {8, 8}; + pinfo->samples_len = 1024.0f; +#elif defined(IRRADIANCE_HL2) + int size[2] = {3, 2}; + pinfo->samples_len = 1024.0f; +#endif - GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - GPU_framebuffer_bind(sldata->probe_filter_fb); - DRW_draw_pass(psl->probe_grid_fill); + int cell_per_row = GPU_texture_width(light_cache->grid_tx.tex) / size[0]; + int x = size[0] * (grid_offset % cell_per_row); + int y = size[1] * (grid_offset / cell_per_row); - common_data->prb_num_render_grid = 1; - /* Reset volume history. */ - stl->effects->volume_current_sample = -1; - common_data->vol_history_alpha = 0.0f; - } - pinfo->update_world = 0; - DRW_viewport_request_redraw(); - /* Do not let this frame accumulate. */ - stl->effects->taa_current_sample = 1; +#ifndef IRRADIANCE_SH_L2 + /* Tweaking parameters to balance perf. vs precision */ + const float bias = 0.0f; + pinfo->samples_len_inv = 1.0f / pinfo->samples_len; + pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2); + pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f; +#else + pinfo->shres = 32; /* Less texture fetches & reduce branches */ + pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */ +#endif - DRW_viewport_matrix_override_set_all(&saved_mats); + /* Start fresh */ + GPU_framebuffer_ensure_config(&fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); + + /* 4 - Compute diffuse irradiance */ + EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max)); + + GPU_framebuffer_ensure_config(&fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, 0) + }); + GPU_framebuffer_bind(fb); + GPU_framebuffer_viewport_set(fb, x, y, size[0], size[1]); + DRW_draw_pass(psl->probe_diffuse_compute); } -static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */ +void EEVEE_lightbake_filter_visibility( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, + struct GPUTexture *UNUSED(rt_depth), struct GPUFrameBuffer *fb, + int grid_offset, float clipsta, float clipend, + float vis_range, float vis_blur, int vis_size) { - EEVEE_LightProbesInfo *pinfo = sldata->probes; EEVEE_PassList *psl = vedata->psl; - if (pinfo->grid_initialized) { - /* Grid is already initialized, nothing to do. */ - return; + EEVEE_LightProbesInfo *pinfo = sldata->probes; + LightCache *light_cache = vedata->stl->g_data->light_cache; + + pinfo->samples_len = 512.0f; /* TODO refine */ + pinfo->samples_len_inv = 1.0f / pinfo->samples_len; + pinfo->shres = 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)vis_size; + + int cell_per_col = GPU_texture_height(light_cache->grid_tx.tex) / vis_size; + int cell_per_row = GPU_texture_width(light_cache->grid_tx.tex) / vis_size; + int x = vis_size * (grid_offset % cell_per_row); + int y = vis_size * ((grid_offset / cell_per_row) % cell_per_col); + int layer = 1 + ((grid_offset / cell_per_row) / cell_per_col); + + GPU_framebuffer_ensure_config(&fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, layer) + }); + GPU_framebuffer_bind(fb); + GPU_framebuffer_viewport_set(fb, x, y, vis_size, vis_size); + DRW_draw_pass(psl->probe_visibility_compute); +} + +/* Actually a simple downsampling */ +static void downsample_planar(void *vedata, int level) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + + const float *size = DRW_viewport_size_get(); + copy_v2_v2(stl->g_data->planar_texel_size, size); + for (int i = 0; i < level - 1; ++i) { + stl->g_data->planar_texel_size[0] /= 2.0f; + stl->g_data->planar_texel_size[1] /= 2.0f; + min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f); + min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f); } - /* Flood fill with world irradiance. */ - GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - GPU_framebuffer_bind(sldata->probe_filter_fb); - DRW_draw_pass(psl->probe_grid_fill); + invert_v2(stl->g_data->planar_texel_size); + + DRW_draw_pass(psl->probe_planar_downsample_ps); +} - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); +static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata) +{ + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; - GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - GPU_framebuffer_bind(sldata->probe_filter_fb); - DRW_draw_pass(psl->probe_grid_fill); + DRW_stats_group_start("Planar Probe Downsample"); - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->planar_pool) + }); - pinfo->grid_initialized = true; + GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata); + DRW_stats_group_end(); } +/** \} */ + void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; - Object *ob; EEVEE_LightProbesInfo *pinfo = sldata->probes; DRWMatrixState saved_mats; @@ -1547,9 +1283,6 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v return; } - EEVEE_planar_reflections_updates(sldata); - DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data); - /* We need to save the Matrices before overidding them */ DRW_viewport_matrix_get_all(&saved_mats); @@ -1561,13 +1294,13 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - LightProbe *prb = (LightProbe *)ob->data; - pinfo->vis_data.collection = prb->visibility_grp; - pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP; - render_scene_to_planar(sldata, vedata, i, ped); - } + /* Rendering happens here! */ + eevee_lightbake_render_scene_to_planars(sldata, vedata); + + /* Make sure no aditionnal visibility check runs after this. */ + pinfo->vis_data.collection = NULL; + + DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data); /* Restore */ common_data->prb_num_planar = pinfo->num_planar; @@ -1576,17 +1309,7 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v /* Prefilter for SSR */ if ((vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { - const int max_lod = 9; - DRW_stats_group_start("Planar Probe Downsample"); - - GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->planar_pool) - }); - GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, max_lod, &downsample_planar, vedata); - /* For shading, save max level of the planar map */ - common_data->prb_lod_planar_max = (float)(max_lod); - DRW_stats_group_end(); + EEVEE_lightbake_filter_planar(vedata); } DRW_viewport_matrix_override_set_all(&saved_mats); @@ -1600,239 +1323,18 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer; } -static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) -{ - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - if (!ped->need_update) { - continue; - } - LightProbe *prb = (LightProbe *)ob->data; - pinfo->vis_data.collection = prb->visibility_grp; - pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP; - render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend); - glossy_filter_probe(sldata, vedata, psl, i, prb->intensity); - ped->need_update = false; - ped->probe_id = i; - if (!ped->ready_to_shade) { - common_data->prb_num_render_cube++; - ped->ready_to_shade = true; - } -#if 0 - printf("Update Cubemap %d\n", i); -#endif - DRW_viewport_request_redraw(); - /* Do not let this frame accumulate. */ - stl->effects->taa_current_sample = 1; - /* Only do one probe per frame */ - return; - } - - pinfo->do_cube_update = false; -} - -static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) -{ - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_LightProbesInfo *pinfo = sldata->probes; - Object *ob; - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - - if (draw_ctx->evil_C != NULL) { - /* Only compute probes if not navigating or in playback */ - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) { - return; - } - } - /* We need to save the Matrices before overidding them */ - DRWMatrixState saved_mats; - DRW_viewport_matrix_get_all(&saved_mats); - /* Make sure grid is initialized. */ - lightprobes_refresh_initialize_grid(sldata, vedata); - /* Reflection probes depend on diffuse lighting thus on irradiance grid, - * so update them first. */ - while (pinfo->updated_bounce < pinfo->num_bounce) { - common_data->prb_num_render_grid = pinfo->num_grid; - /* TODO(sergey): This logic can be split into smaller functions. */ - for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - if (!ped->need_update) { - continue; - } - EEVEE_LightGrid *egrid = &pinfo->grid_data[i]; - LightProbe *prb = (LightProbe *)ob->data; - /* Find the next cell corresponding to the current level. */ - bool valid_cell = false; - int cell_id = ped->updated_cells; - float pos[3], grid_loc[3]; - /* Other levels */ - int current_stride = 1 << max_ii(0, ped->max_lvl - ped->updated_lvl); - int prev_stride = current_stride << 1; - bool do_rendering = true; - while (!valid_cell) { - cell_id = ped->updated_cells; - lightprobe_cell_grid_location_get(egrid, cell_id, grid_loc); - if (ped->updated_lvl == 0 && cell_id == 0) { - valid_cell = true; - ped->updated_cells = ped->num_cell; - continue; - } - else if (((((int)grid_loc[0] % current_stride) == 0) && - (((int)grid_loc[1] % current_stride) == 0) && - (((int)grid_loc[2] % current_stride) == 0)) && - !((((int)grid_loc[0] % prev_stride) == 0) && - (((int)grid_loc[1] % prev_stride) == 0) && - (((int)grid_loc[2] % prev_stride) == 0))) - { - valid_cell = true; - } - ped->updated_cells++; - if (ped->updated_cells > ped->num_cell) { - do_rendering = false; - break; - } - } - if (do_rendering) { - lightprobe_cell_world_location_get(egrid, grid_loc, pos); - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - /* Temporary Remove all probes. */ - int tmp_num_render_grid = common_data->prb_num_render_grid; - int tmp_num_render_cube = common_data->prb_num_render_cube; - int tmp_num_planar = common_data->prb_num_planar; - float tmp_level_bias = egrid->level_bias; - common_data->prb_num_render_cube = 0; - common_data->prb_num_planar = 0; - /* Use light from previous bounce when capturing radiance. */ - if (pinfo->updated_bounce == 0) { - /* But not on first bounce. */ - common_data->prb_num_render_grid = 0; - } - else { - /* Remove bias */ - egrid->level_bias = (float)(1 << 0); - DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); - } - pinfo->vis_data.collection = prb->visibility_grp; - pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP; - render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend); - diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id, - prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur, - prb->intensity); - /* To see what is going on. */ - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - /* Restore */ - common_data->prb_num_render_cube = tmp_num_render_cube; - pinfo->num_planar = tmp_num_planar; - if (pinfo->updated_bounce == 0) { - common_data->prb_num_render_grid = tmp_num_render_grid; - } - else { - egrid->level_bias = tmp_level_bias; - DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); - } -#if 0 - printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n", - i, cell_id + 1, ped->num_cell, pinfo->updated_bounce + 1, pinfo->num_bounce); -#endif - } - if (ped->updated_cells >= ped->num_cell) { - ped->updated_lvl++; - ped->updated_cells = 0; - if (ped->updated_lvl > ped->max_lvl) { - ped->need_update = false; - } - egrid->level_bias = (float)(1 << max_ii(0, ped->max_lvl - ped->updated_lvl + 1)); - DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); - } - /* Only do one probe per frame */ - DRW_viewport_request_redraw(); - /* Do not let this frame accumulate. */ - stl->effects->taa_current_sample = 1; - /* Reset volume history. */ - stl->effects->volume_current_sample = -1; - common_data->vol_history_alpha = 0.0f; - /* Restore matrices */ - DRW_viewport_matrix_override_set_all(&saved_mats); - return; - } - - pinfo->updated_bounce++; - common_data->prb_num_render_grid = pinfo->num_grid; - - if (pinfo->updated_bounce < pinfo->num_bounce) { - /* Retag all grids to update for next bounce */ - for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - ped->need_update = true; - ped->updated_cells = 0; - ped->updated_lvl = 0; - } - /* Reset the next buffer so we can see the progress. */ - /* irradiance_rt is already the next rt because of the previous SWAP */ - GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - GPU_framebuffer_bind(sldata->probe_filter_fb); - DRW_draw_pass(psl->probe_grid_fill); - - GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); - /* Swap AFTER */ - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - } - } - /* Refresh cube probe when needed. */ - lightprobes_refresh_cube(sldata, vedata); - /* Restore matrices */ - DRW_viewport_matrix_override_set_all(&saved_mats); -} - -bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) -{ - EEVEE_LightProbesInfo *pinfo = sldata->probes; - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - - return ((pinfo->do_cube_update == false) && - (pinfo->updated_bounce == pinfo->num_bounce) && - (common_data->prb_num_render_cube == pinfo->num_cube)); -} - void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_LightProbesInfo *pinfo = sldata->probes; - - /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ - common_data->spec_toggle = false; - common_data->ssr_toggle = false; - common_data->sss_toggle = false; - - /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */ - float tmp_ao_dist = common_data->ao_dist; - float tmp_ao_settings = common_data->ao_settings; - common_data->ao_settings = 0.0f; - common_data->ao_dist = 0.0f; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); + LightCache *light_cache = vedata->stl->g_data->light_cache; - /* Render world in priority */ - if (pinfo->update_world) { - lightprobes_refresh_world(sldata, vedata); - } - else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false && pinfo->all_materials_updated) { - lightprobes_refresh_all_no_world(sldata, vedata); + if (light_cache->flag & LIGHTCACHE_UPDATE_WORLD) { + DRWMatrixState saved_mats; + DRW_viewport_matrix_get_all(&saved_mats); + EEVEE_lightbake_update_world_quick(sldata, vedata, scene_eval); + DRW_viewport_matrix_override_set_all(&saved_mats); } - - /* Restore */ - common_data->spec_toggle = true; - common_data->ssr_toggle = true; - common_data->sss_toggle = true; - common_data->ao_dist = tmp_ao_dist; - common_data->ao_settings = tmp_ao_settings; } void EEVEE_lightprobes_free(void) |