Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-07-10 16:02:25 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-07-10 16:31:34 +0300
commit1a43e081873415754950766edaddad220adf67bc (patch)
tree6a4e61b2337606daf442973d9f82e1d56b906a98 /source/blender/draw/engines/eevee/eevee_lightprobes.c
parent97f90d48a02eef89949532b166f57ea178ee5a87 (diff)
Eevee: LightCache: Initial Implementation
This separate probe rendering from viewport rendering, making possible to run the baking in another thread (non blocking and faster). The baked lighting is saved in the blend file. Nothing needs to be recomputed on load. There is a few missing bits / bugs: - Cache cannot be saved to disk as a separate file, it is saved in the DNA for now making file larger and memory usage higher. - Auto update only cubemaps does update the grids (bug). - Probes cannot be updated individually (considered as dynamic). - Light Cache cannot be (re)generated during render.
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_lightprobes.c')
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c1882
1 files changed, 698 insertions, 1184 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 95b015cb044..1cb9a957211 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 {
@@ -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_len = 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_len = (int)ceilf((float)total_samples / (float)(layer_len - 1));
- r_size[0] = visibility_size * max_ii(1, min_ii(texel_len, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
- r_size[1] = visibility_size * max_ii(1, (texel_len / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
- r_size[2] = layer_len;
+ 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,178 +300,65 @@ 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;
- }
-
- 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;
-
- sldata->probes->target_size = prop_cubemap_res >> 1;
-
- DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
- DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
- }
-
- 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;
- }
-
- if (update_all) {
- sldata->probes->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, 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);
- }
-
- 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)
- });
- }
-
/* 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);
}
-
- if (!e_data.depth_placeholder) {
- e_data.depth_placeholder = DRW_texture_create_2D(1, 1, GPU_DEPTH_COMPONENT24, 0, 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);
- }
}
-void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+/* 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_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- /* Make sure no aditionnal visibility check runs by default. */
- pinfo->vis_data.collection = NULL;
-
- 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();
- DRWShadingGroup *grp = NULL;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- World *wo = scene->world;
-
- float *col = ts.colorBackground;
-
- /* LookDev */
- EEVEE_lookdev_cache_init(vedata, &grp, e_data.probe_default_studiolight_sh, psl->probe_background, wo, pinfo);
- /* 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);
-
- switch (status) {
- case GPU_MAT_SUCCESS:
- 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 (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;
- }
- }
- 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. */
- if (grp == NULL) {
- grp = DRW_shgroup_create(e_data.probe_default_sh, psl->probe_background);
- DRW_shgroup_uniform_vec3(grp, "color", col, 1);
- DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- DRW_shgroup_call_add(grp, geom, NULL);
- }
- }
-
{
psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR);
@@ -489,7 +374,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
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_uniform_texture(grp, "probeHdr", rt_color);
DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
@@ -507,7 +392,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
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);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
@@ -526,7 +411,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
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);
+ DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
@@ -536,37 +421,115 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
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);
+ DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &light_cache->grid_tx.tex);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
}
+}
+
+void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ 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);
+
+ pinfo->num_planar = 0;
+ pinfo->vis_data.collection = NULL;
+ pinfo->do_grid_update = false;
+ pinfo->do_cube_update = false;
{
+ 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();
+ DRWShadingGroup *grp = NULL;
+
+ Scene *scene = draw_ctx->scene;
+ World *wo = scene->world;
+
+ float *col = ts.colorBackground;
+
+ /* LookDev */
+ EEVEE_lookdev_cache_init(vedata, &grp, e_data.probe_default_studiolight_sh, psl->probe_background, wo, pinfo);
+ /* END */
+ if (!grp && wo) {
+ col = &wo->horr;
+
+ if (wo->use_nodes && wo->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
+
+ GPUMaterialStatus status = GPU_material_status(gpumat);
+
+ switch (status) {
+ case GPU_MAT_SUCCESS:
+ 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);
+ break;
+ default:
+ col = error_col;
+ break;
+ }
+ }
+ }
+
+ /* Fallback if shader fails or if not using nodetree. */
+ if (grp == NULL) {
+ grp = DRW_shgroup_create(e_data.probe_default_sh, psl->probe_background);
+ DRW_shgroup_uniform_vec3(grp, "color", col, 1);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ 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(),
@@ -574,6 +537,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);
@@ -585,514 +551,560 @@ 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_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);
+ }
+
+ pinfo->num_planar++;
}
+ else {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ 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;
+ }
+ }
+}
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *egrid, int *offset)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
- ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
+ 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)));
+}
- if ((probe->type == LIGHTPROBE_TYPE_GRID) &&
- ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES))
- {
- printf("Too much grid samples !!!\n");
- return;
- }
+void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprobe)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
- if (ped->need_full_update) {
- ped->need_full_update = false;
+ /* Update transforms */
+ copy_v3_v3(eprobe->position, ob->obmat[3]);
- 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;
- }
- }
+ /* Attenuation */
+ eprobe->attenuation_type = probe->attenuation_type;
+ eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff);
- if (pinfo->update_world) {
- ped->need_update = true;
- ped->updated_cells = 0;
- ped->updated_lvl = 0;
- ped->probe_id = 0;
- }
+ unit_m4(eprobe->attenuationmat);
+ scale_m4_fl(eprobe->attenuationmat, probe->distinf);
+ mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat);
+ invert_m4(eprobe->attenuationmat);
- pinfo->do_cube_update |= ped->need_update;
+ /* Parallax */
+ unit_m4(eprobe->parallaxmat);
- 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;
+ 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);
}
+
+ mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
+ invert_m4(eprobe->parallaxmat);
+}
+
+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;
}
-/* TODO find a nice name to push it to math_matrix.c */
-static void scale_m4_v3(float R[4][4], float v[3])
+static void lightbake_planar_compute_render_matrices(
+ EEVEE_PlanarReflection *eplanar, DRWMatrixState *r_matstate, const float viewmat[4][4])
{
- for (int i = 0; i < 4; ++i)
- mul_v3_v3(R[i], v);
+ /* 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);
}
-static void EEVEE_planar_reflections_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl)
+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_StorageList *stl = vedata->stl;
+ LightCache *light_cache = stl->g_data->light_cache;
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;
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ eevee_lightprobes_extract_from_cache(sldata->probes, light_cache);
- ped->probe_id = i;
+ DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- /* 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);
+ /* 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;
+ }
+ planar_pool_ensure_alloc(vedata, pinfo->num_planar);
+
+ /* 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 (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;
+ }
+
+ /* Use a notifier to trigger the operator after drawing. */
+ WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig);
}
}
}
-static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata)
+/* -------------------------------------------------------------------- */
+
+/** \name Rendering
+ * \{ */
+
+typedef struct EEVEE_BakeRenderData{
+ EEVEE_Data *vedata;
+ EEVEE_ViewLayerData *sldata;
+ struct GPUFrameBuffer **face_fb; /* should contain 6 framebuffer */
+} EEVEE_BakeRenderData;
+
+static void render_cubemap(
+ void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data,
+ const float pos[3], float clipsta, float clipend)
{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
- float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4];
+ DRWMatrixState matstate;
- float viewmat[4][4];
- DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ /* Move to capture position */
+ float posmat[4][4];
+ unit_m4(posmat);
+ negate_v3_v3(posmat[3], pos);
- 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;
+ perspective_m4(matstate.winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
- /* 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;
+ /* 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);
+
+ DRW_viewport_matrix_override_set_all(&matstate);
+
+ callback(i, user_data);
}
}
-static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl)
+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;
- Object *ob;
+ DRWMatrixState matstate;
- /* 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);
+ float original_viewmat[4][4];
+ DRW_viewport_matrix_get(original_viewmat, DRW_MAT_VIEW);
- /* Update transforms */
- copy_v3_v3(eprobe->position, ob->obmat[3]);
+ 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);
- /* Attenuation */
- eprobe->attenuation_type = probe->attenuation_type;
- eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff);
+ callback(i, user_data);
+ }
+}
- unit_m4(eprobe->attenuationmat);
- scale_m4_fl(eprobe->attenuationmat, probe->distinf);
- mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat);
- invert_m4(eprobe->attenuationmat);
+static void lightbake_render_world_face(int face, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_PassList *psl = user_data->vedata->psl;
+ struct GPUFrameBuffer **face_fb = user_data->face_fb;
- /* 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;
- }
+ /* 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);
+}
- unit_m4(eprobe->parallaxmat);
- scale_m4_fl(eprobe->parallaxmat, dist);
- mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
- invert_m4(eprobe->parallaxmat);
+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
+ };
- /* 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);
- }
- }
+ render_cubemap(lightbake_render_world_face, &brdata, (float[3]){0.0f}, 1.0f, 10.0f);
+}
- /* 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);
+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;
- /* 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;
- }
+ /* Be sure that cascaded shadow maps are updated. */
+ EEVEE_draw_shadows(sldata, psl);
- /* 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);
+ GPU_framebuffer_bind(face_fb[face]);
+ GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
- /* 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);
- }
- }
+ 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);
}
-void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+/* 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_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .sldata = sldata,
+ .face_fb = face_fb
+ };
+
+ render_cubemap(lightbake_render_scene_face, &brdata, pos, near_clip, far_clip);
+}
+
+static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *user_data)
+{
+ 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;
- Object *ob;
+ EEVEE_PlanarReflection *eplanar = pinfo->planar_data + layer;
- /* 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;
- }
+ GPU_framebuffer_ensure_config(&fbl->planarref_fb, {
+ GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer),
+ GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer)
+ });
- 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;
- }
+ /* Use visibility info for this planar reflection. */
+ pinfo->vis_data = pinfo->planar_vis_tests[layer];
- int irr_size[3];
- irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, irr_size);
+ /* 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;
- 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);
- }
+ /* Be sure that cascaded shadow maps are updated. */
+ DRW_stats_group_start("Planar Reflection");
- /* XXX this should be run each frame as it ensure planar_depth is set */
- planar_pool_ensure_alloc(vedata, pinfo->num_planar);
+ /* 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();
+ /* 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);
- 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;
- }
+ GPU_framebuffer_bind(fbl->planarref_fb);
+ GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
- 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;
- }
- }
+ /* Slight modification: we handle refraction as normal
+ * shading and don't do SSRefraction. */
-#ifdef IRRADIANCE_SH_L2
- /* we need a signed format for Spherical Harmonics */
- int irradiance_format = GPU_RGBA16F;
-#else
- int irradiance_format = GPU_RGBA8;
-#endif
+ 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);
- 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;
- }
+ DRW_draw_pass(psl->probe_background);
+ EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
+ EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer);
- 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;
- }
- }
+ GPU_framebuffer_bind(fbl->planarref_fb);
- 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;
+ /* Shading pass */
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
+ DRW_draw_pass(psl->refract_pass);
+
+ /* Transparent */
+ if (DRW_state_is_image_render()) {
+ /* Do the reordering only for offline because it can be costly. */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
}
+ DRW_draw_pass(psl->transparent_pass);
- EEVEE_planar_reflections_cache_finish(sldata, vedata->stl);
+ DRW_state_invert_facing();
+ DRW_state_clip_planes_reset();
- EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl);
+ DRW_stats_group_end();
- DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
- DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
+ /* Restore */
+ txl->planar_pool = tmp_planar_pool;
+ txl->planar_depth = tmp_planar_depth;
}
-static void downsample_planar(void *vedata, int level)
+static void eevee_lightbake_render_scene_to_planars(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- 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);
- }
- invert_v2(stl->g_data->planar_texel_size);
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .sldata = sldata,
+ };
- DRW_draw_pass(psl->probe_planar_downsample_ps);
+ render_reflections(lightbake_render_scene_reflected, &brdata, sldata->probes->planar_data, sldata->probes->num_planar);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
-/* 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)
+/** \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;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- pinfo->intensity_fac = intensity;
+ float target_size = (float)GPU_texture_width(rt_color);
/* Max lod used from the render target probe */
- pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f;
+ pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f;
+ pinfo->intensity_fac = intensity;
/* Start fresh */
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&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));
+ EEVEE_downsample_cube_buffer(vedata, rt_color, (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++) {
+ 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 / mipsize;
- pinfo->padding_size = powf(2.0f, (float)(maxlevel - min_lod_level - 1 - i));
+ 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 = (float)i / ((float)maxlevel - 4.0f);
+ 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 */
@@ -1110,35 +1122,34 @@ static void glossy_filter_probe(
#endif
pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- pinfo->lodfactor = bias + 0.5f * log((float)(pinfo->target_size * pinfo->target_size) * pinfo->samples_len_inv) / log(2);
+ pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2);
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE_MIP(sldata->probe_pool, i)
+ GPU_ATTACHMENT_TEXTURE_MIP(light_cache->cube_tx.tex, i)
});
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- GPU_framebuffer_viewport_set(sldata->probe_filter_fb, 0, 0, mipsize, mipsize);
+ 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);
}
- /* 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)
+/* 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_PassList *psl = vedata->psl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- pinfo->intensity_fac = intensity;
+ float target_size = (float)GPU_texture_width(rt_color);
- int pool_size[3];
- irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, pool_size);
+ pinfo->intensity_fac = intensity;
/* find cell position on the virtual 3D texture */
/* NOTE : Keep in sync with load_irradiance_cell() */
@@ -1152,377 +1163,114 @@ static void diffuse_filter_probe(
pinfo->samples_len = 1024.0f;
#endif
- 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);
+ 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);
#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)(pinfo->target_size * pinfo->target_size) * pinfo->samples_len_inv) / log(2);
- pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f;
+ 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
/* Start fresh */
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_NONE
});
- /* 4 - Compute spherical harmonics */
- EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max));
+ /* 4 - Compute diffuse irradiance */
+ EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max));
- GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, {
+ GPU_framebuffer_ensure_config(&fb, {
GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, 0)
+ GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, 0)
});
- GPU_framebuffer_bind(sldata->probe_filter_fb);
- GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, size[0], size[1]);
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, x, y, size[0], size[1]);
DRW_draw_pass(psl->probe_diffuse_compute);
-
- /* World irradiance have no visibility */
- if (offset > 0) {
- /* Compute visibility */
- pinfo->samples_len = 512.0f; /* TODO refine */
- pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
- 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 the scene to the probe_rt texture. */
-static void render_scene_to_probe(
+/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */
+void EEVEE_lightbake_filter_visibility(
EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
- const float pos[3], float clipsta, float clipend)
+ 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_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
- 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);
-
- /* 1 - Render to each cube-face individually.
- * We do this instead of using geometry shader because a) it's faster,
- * b) it's easier than fixing the node-tree shaders (for view dependent effects). */
- pinfo->layer = 0;
- perspective_m4(winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
-
- /* Avoid using the texture attached to framebuffer when rendering. */
- /* XXX */
- GPUTexture *tmp_planar_pool = txl->planar_pool;
- GPUTexture *tmp_maxz = txl->maxzbuffer;
- 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);
-
- 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 back-face 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);
- 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)
+ 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(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 */
- EEVEE_draw_default_passes(psl);
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
- DRW_draw_pass(psl->refract_pass);
-
- /* Transparent */
- if (DRW_state_is_image_render()) {
- /* Do the reordering only for offline because it can be costly. */
- DRW_pass_sort_shgroup_z(psl->transparent_pass);
- }
- DRW_draw_pass(psl->transparent_pass);
-
- DRW_state_invert_facing();
- DRW_state_clip_planes_reset();
-
- 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;
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, x, y, vis_size, vis_size);
+ DRW_draw_pass(psl->probe_visibility_compute);
}
-static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
+/* Actually a simple downsampling */
+static void downsample_planar(void *vedata, int level)
{
- 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];
-
- /* For world probe, we don't need to clear since we render the background directly. */
- pinfo->layer = 0;
-
- perspective_m4(winmat, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
- invert_m4_m4(wininv, winmat);
-
- 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);
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- 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);
+ 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);
}
-}
-
-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]));
-}
+ invert_v2(stl->g_data->planar_texel_size);
-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);
+ DRW_draw_pass(psl->probe_planar_downsample_ps);
}
-static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata)
{
- 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;
-
- /* We need to save the Matrices before overidding them */
- DRW_viewport_matrix_get_all(&saved_mats);
-
- 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);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ 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");
- 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;
+ GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->planar_pool)
+ });
- DRW_viewport_matrix_override_set_all(&saved_mats);
+ GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata);
+ DRW_stats_group_end();
}
-static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
-{
- EEVEE_LightProbesInfo *pinfo = sldata->probes;
- EEVEE_PassList *psl = vedata->psl;
- if (pinfo->grid_initialized) {
- /* Grid is already initialized, nothing to do. */
- return;
- }
- /* 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);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- 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);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- pinfo->grid_initialized = true;
-}
+/** \} */
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;
@@ -1533,9 +1281,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);
@@ -1547,13 +1292,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;
@@ -1562,17 +1307,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);
@@ -1586,239 +1321,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)