From 65e087ef492db80fbaa016216fd2bd6607e4edc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 6 Apr 2023 17:32:39 +0200 Subject: [PATCH 1/9] LightProbe: Add new object level irradiance cache --- source/blender/blenkernel/BKE_lightprobe.h | 39 ++++ .../blender/blenkernel/intern/lightprobe.cc | 173 ++++++++++++++++++ source/blender/blenkernel/intern/object.cc | 26 +++ .../blender/editors/render/render_intern.hh | 3 + source/blender/editors/render/render_ops.cc | 3 + .../blender/editors/render/render_shading.cc | 126 +++++++++++++ .../blender/makesdna/DNA_lightprobe_types.h | 111 ++++++++++- source/blender/makesdna/DNA_object_types.h | 10 + 8 files changed, 488 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h index d7f9ad9a5bd..b976a986086 100644 --- a/source/blender/blenkernel/BKE_lightprobe.h +++ b/source/blender/blenkernel/BKE_lightprobe.h @@ -14,10 +14,49 @@ extern "C" { struct LightProbe; struct Main; +struct BlendWriter; +struct BlendDataReader; +struct LightProbeGridCache; +struct Object; void BKE_lightprobe_type_set(struct LightProbe *probe, short lightprobe_type); void *BKE_lightprobe_add(struct Main *bmain, const char *name); +void BKE_lightprobe_grid_cache_blend_write(struct BlendWriter *writer, + struct LightProbeGridCache **grid_caches, + int grid_caches_len); + +void BKE_lightprobe_grid_cache_blend_read(struct BlendDataReader *reader, + struct LightProbeGridCache **grid_caches, + int grid_caches_len); + +/** + * Create a single empty irradiance grid cache. + */ +struct LightProbeGridCache *BKE_lightprobe_grid_cache_create(void); + +/** + * Free a single grid cache. + */ +void BKE_lightprobe_grid_cache_free(struct LightProbeGridCache *cache); + +/** + * Create the grid cache list depending on the lightprobe baking settings. + * The list is left empty to be filled by the baking process. + */ +void BKE_lightprobe_grid_caches_create(struct Object *object); + +/** + * Free all irradiance grids allocated for the given object. + */ +void BKE_lightprobe_grid_caches_free(struct Object *object); + +/** + * Return the number of sample stored inside an irradiance cache. + * This depends on the light cache type. + */ +int64_t BKE_lightprobe_grid_cache_sample_count(const struct LightProbeGridCache *cache); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/lightprobe.cc b/source/blender/blenkernel/intern/lightprobe.cc index 4ad560d8245..ee14d9bbd1e 100644 --- a/source/blender/blenkernel/intern/lightprobe.cc +++ b/source/blender/blenkernel/intern/lightprobe.cc @@ -12,6 +12,8 @@ #include "DNA_lightprobe_types.h" #include "DNA_object_types.h" +#include "BLI_math_base.h" +#include "BLI_span.hh" #include "BLI_utildefines.h" #include "BKE_anim_data.h" @@ -129,3 +131,174 @@ void *BKE_lightprobe_add(Main *bmain, const char *name) return probe; } + +void BKE_lightprobe_grid_cache_blend_write(BlendWriter *writer, + LightProbeGridCache **grid_caches, + int grid_caches_len) +{ + blender::Span caches(grid_caches, grid_caches_len); + for (const LightProbeGridCache *cache : caches) { + if (cache == nullptr) { + continue; + } + + BLO_write_struct(writer, LightProbeGridCache, cache); + + if (cache->block_infos != nullptr) { + BLO_write_struct_array(writer, LightProbeGridCache, cache->block_len, cache->block_infos); + } + + int64_t sample_count = BKE_lightprobe_grid_cache_sample_count(cache); + + if (cache->irradiance.L0 != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L0); + } + if (cache->irradiance.L1_a != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_a); + } + if (cache->irradiance.L1_b != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_b); + } + if (cache->irradiance.L1_c != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_c); + } + + if (cache->visibility.L0 != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L0); + } + if (cache->visibility.L1_a != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_a); + } + if (cache->visibility.L1_b != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_b); + } + if (cache->visibility.L1_c != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_c); + } + + if (cache->connectivity.bitmask != nullptr) { + BLO_write_struct_array( + writer, LightProbeGridCache, sample_count, cache->connectivity.bitmask); + } + } +} + +void BKE_lightprobe_grid_cache_blend_read(BlendDataReader *reader, + LightProbeGridCache **grid_caches, + int grid_caches_len) +{ + blender::MutableSpan caches(grid_caches, grid_caches_len); + for (LightProbeGridCache *&cache : caches) { + if (cache == nullptr) { + continue; + } + + BLO_read_data_address(reader, &cache); + + if (cache->block_infos != nullptr) { + BLO_read_data_address(reader, &cache->block_infos); + } + + /* Baking data is not stored. */ + cache->baking.L0 = nullptr; + cache->baking.L1_a = nullptr; + cache->baking.L1_b = nullptr; + cache->baking.L1_c = nullptr; + + if (cache->irradiance.L0 != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L0); + } + if (cache->irradiance.L1_a != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L1_a); + } + if (cache->irradiance.L1_b != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L1_b); + } + if (cache->irradiance.L1_c != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L1_c); + } + + if (cache->visibility.L0 != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L0); + } + if (cache->visibility.L1_a != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L1_a); + } + if (cache->visibility.L1_b != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L1_b); + } + if (cache->visibility.L1_c != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L1_c); + } + + if (cache->connectivity.bitmask != nullptr) { + BLO_read_data_address(reader, &cache->connectivity.bitmask); + } + } +} + +template static void spherical_harmonic_free(T &data) +{ + MEM_SAFE_FREE(data.L0); + MEM_SAFE_FREE(data.L1_a); + MEM_SAFE_FREE(data.L1_b); + MEM_SAFE_FREE(data.L1_c); +} + +LightProbeGridCache *BKE_lightprobe_grid_cache_create() +{ + LightProbeGridCache *cache = static_cast( + MEM_callocN(sizeof(LightProbeGridCache), "LightProbeGridCache")); + cache->cache_type = LIGHTPROBE_CACHE_TYPE_NONE; + cache->data_layout = LIGHTPROBE_CACHE_UNIFORM_GRID; + return cache; +} + +void BKE_lightprobe_grid_cache_free(LightProbeGridCache *cache) +{ + MEM_SAFE_FREE(cache->block_infos); + spherical_harmonic_free(cache->baking); + spherical_harmonic_free(cache->irradiance); + spherical_harmonic_free(cache->visibility); + MEM_SAFE_FREE(cache->connectivity.bitmask); + + MEM_SAFE_FREE(cache); +} + +void BKE_lightprobe_grid_caches_create(Object *object) +{ + BLI_assert(object->irradiance_caches == nullptr); + + /* Single cache for now. */ + const int grid_caches_len = 1; + LightProbeGridCache **grid_caches = static_cast( + MEM_callocN(sizeof(LightProbeGridCache *) * grid_caches_len, "irradiance_caches")); + object->irradiance_caches = grid_caches; + object->irradiance_caches_len = grid_caches_len; +} + +void BKE_lightprobe_grid_caches_free(Object *object) +{ + if (object->irradiance_caches == nullptr) { + return; + } + + blender::MutableSpan caches(object->irradiance_caches, + object->irradiance_caches_len); + for (LightProbeGridCache *cache : caches) { + if (cache != nullptr) { + BKE_lightprobe_grid_cache_free(cache); + } + } + MEM_SAFE_FREE(object->irradiance_caches); + object->irradiance_caches_len = 0; +} + +int64_t BKE_lightprobe_grid_cache_sample_count(const LightProbeGridCache *cache) +{ + if (cache->cache_type == LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION) { + return cache->block_len * cube_i(cache->block_size); + } + /* LIGHTPROBE_CACHE_UNIFORM_GRID */ + return cache->size[0] * cache->size[1] * cache->size[2]; +} diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 7eca790e36f..e1b4afaec91 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -267,6 +267,19 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in if (ob_src->lightgroup) { ob_dst->lightgroup = (LightgroupMembership *)MEM_dupallocN(ob_src->lightgroup); } + + if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) { + /* Reference the original object data. */ + ob_dst->irradiance_caches = ob_src->irradiance_caches; + ob_dst->irradiance_caches_len = ob_src->irradiance_caches_len; + ob_dst->irradiance_caches_shared = true; + } + else { + /* Do not copy lightprobe's cache. */ + ob_dst->irradiance_caches = nullptr; + ob_dst->irradiance_caches_len = 0; + ob_dst->irradiance_caches_shared = false; + } } static void object_free_data(ID *id) @@ -319,6 +332,10 @@ static void object_free_data(ID *id) BKE_previewimg_free(&ob->preview); MEM_SAFE_FREE(ob->lightgroup); + + if (ob->irradiance_caches_shared == false) { + BKE_lightprobe_grid_caches_free(ob); + } } static void library_foreach_modifiersForeachIDLink(void *user_data, @@ -597,6 +614,12 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre if (ob->lightgroup) { BLO_write_struct(writer, LightgroupMembership, ob->lightgroup); } + + if (ob->irradiance_caches) { + BLO_write_pointer_array(writer, ob->irradiance_caches_len, ob->irradiance_caches); + BKE_lightprobe_grid_cache_blend_write( + writer, ob->irradiance_caches, ob->irradiance_caches_len); + } } /* XXX deprecated - old animation system */ @@ -815,6 +838,9 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id) BKE_previewimg_blend_read(reader, ob->preview); BLO_read_data_address(reader, &ob->lightgroup); + + BLO_read_pointer_array(reader, (void **)&ob->irradiance_caches); + BKE_lightprobe_grid_cache_blend_read(reader, ob->irradiance_caches, ob->irradiance_caches_len); } /* XXX deprecated - old animation system */ diff --git a/source/blender/editors/render/render_intern.hh b/source/blender/editors/render/render_intern.hh index e9adf760ee7..2497c59ab4c 100644 --- a/source/blender/editors/render/render_intern.hh +++ b/source/blender/editors/render/render_intern.hh @@ -41,6 +41,9 @@ void SCENE_OT_view_layer_remove_unused_lightgroups(struct wmOperatorType *ot); void SCENE_OT_light_cache_bake(struct wmOperatorType *ot); void SCENE_OT_light_cache_free(struct wmOperatorType *ot); +void OBJECT_OT_lightprobe_cache_bake(struct wmOperatorType *ot); +void OBJECT_OT_lightprobe_cache_free(struct wmOperatorType *ot); + void SCENE_OT_render_view_add(struct wmOperatorType *ot); void SCENE_OT_render_view_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_ops.cc b/source/blender/editors/render/render_ops.cc index 933a4d0cc88..84ed29fade7 100644 --- a/source/blender/editors/render/render_ops.cc +++ b/source/blender/editors/render/render_ops.cc @@ -28,6 +28,9 @@ void ED_operatortypes_render() WM_operatortype_append(OBJECT_OT_material_slot_move); WM_operatortype_append(OBJECT_OT_material_slot_remove_unused); + WM_operatortype_append(OBJECT_OT_lightprobe_cache_bake); + WM_operatortype_append(OBJECT_OT_lightprobe_cache_free); + WM_operatortype_append(MATERIAL_OT_new); WM_operatortype_append(TEXTURE_OT_new); WM_operatortype_append(WORLD_OT_new); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 452b6228e50..086e5f13f2f 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -37,6 +37,7 @@ #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" +#include "BKE_lightprobe.h" #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_material.h" @@ -53,6 +54,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #ifdef WITH_FREESTYLE # include "BKE_freestyle.h" @@ -1492,6 +1494,87 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); } +/* NOTE: New version destined to replace the old lightcache bake operator. */ + +static int lightprobe_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) +{ + Scene *scene = CTX_data_scene(C); + Object *active_ob = CTX_data_active_object(C); + + BKE_lightprobe_grid_caches_free(active_ob); + BKE_lightprobe_grid_caches_create(active_ob); + + DEG_id_tag_update(&active_ob->id, ID_RECALC_COPY_ON_WRITE); + + WM_event_add_modal_handler(C, op); + + /* store actual owner of job, so modal operator could check for it, + * the reason of this is that active scene could change when rendering + * several layers from compositor #31800. */ + op->customdata = scene; + + WM_cursor_wait(false); + + return OPERATOR_RUNNING_MODAL; +} + +static int lightprobe_cache_bake_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Scene *scene = (Scene *)op->customdata; + + /* No running bake, remove handler and pass through. */ + if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_LIGHT_BAKE)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + + /* Running bake. */ + switch (event->type) { + case EVT_ESCKEY: + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_PASS_THROUGH; +} + +static void lightprobe_cache_bake_cancel(bContext *C, wmOperator *op) +{ + wmWindowManager *wm = CTX_wm_manager(C); + Scene *scene = (Scene *)op->customdata; + + /* Kill on cancel, because job is using op->reports. */ + WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); +} + +/* Executes blocking render. */ +static int lightprobe_cache_bake_exec(bContext * /*C*/, wmOperator * /*op*/) +{ + return OPERATOR_FINISHED; +} + +void OBJECT_OT_lightprobe_cache_bake(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake Light Cache"; + ot->idname = "OBJECT_OT_lightprobe_cache_bake"; + ot->description = "Bake the active view layer lighting"; + + /* api callbacks */ + ot->invoke = lightprobe_cache_bake_invoke; + ot->modal = lightprobe_cache_bake_modal; + ot->cancel = lightprobe_cache_bake_cancel; + ot->exec = lightprobe_cache_bake_exec; + + ot->prop = RNA_def_int(ot->srna, + "delay", + 0, + 0, + 2000, + "Delay", + "Delay in millisecond before baking starts", + 0, + 2000); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1541,6 +1624,49 @@ void SCENE_OT_light_cache_free(wmOperatorType *ot) ot->poll = light_cache_free_poll; } +/* NOTE: New version destined to replace the old lightcache bake operator. */ + +static bool lightprobe_cache_free_poll(bContext *C) +{ + Object *object = CTX_data_active_object(C); + + return object && object->irradiance_caches != nullptr; +} + +static int lightprobe_cache_free_exec(bContext *C, wmOperator * /*op*/) +{ + Scene *scene = CTX_data_scene(C); + Object *object = CTX_data_active_object(C); + + /* Kill potential bake job first (see #57011). */ + wmWindowManager *wm = CTX_wm_manager(C); + WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); + + if (object->irradiance_caches == nullptr) { + return OPERATOR_CANCELLED; + } + + BKE_lightprobe_grid_caches_free(object); + + DEG_id_tag_update(&object->id, ID_RECALC_COPY_ON_WRITE); + + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, scene); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_lightprobe_cache_free(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Light Cache"; + ot->idname = "OBJECT_OT_lightprobe_cache_free"; + ot->description = "Delete cached indirect lighting"; + + /* api callbacks */ + ot->exec = lightprobe_cache_free_exec; + ot->poll = lightprobe_cache_free_poll; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 5b5bc4c7392..c9c11725c32 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -61,9 +61,6 @@ typedef struct LightProbe { struct Image *image; /** Object visibility group, inclusive or exclusive. */ struct Collection *visibility_grp; - - /* Runtime display data */ - float distfalloff, distgridinf; } LightProbe; /* Probe->type */ @@ -201,6 +198,114 @@ enum { LIGHTCACHETEX_UINT = (1 << 2), }; +/* -------------------------------------------------------------------- */ +/** \name Irradiance grid data storage + * + * Each spherical harmonic band is stored separately. This allow loading only a specific band. + * The layout of each array is set by the #LightProbeGridType. + * Any unavailable data is be set to nullptr. + * \{ */ + +/** + * Irradiance data (RGB) stored along visibility (A). + * This is the format used during baking and is used for visualizing the baking process. + */ +typedef struct LightProbeBakingData { + float (*L0)[4]; + float (*L1_a)[4]; + float (*L1_b)[4]; + float (*L1_c)[4]; +} LightProbeBakingData; + +/** + * Irradiance stored as RGB triple using scene referred color space. + */ +typedef struct LightProbeIrradianceData { + float (*L0)[3]; + float (*L1_a)[3]; + float (*L1_b)[3]; + float (*L1_c)[3]; +} LightProbeIrradianceData; + +/** + * Normalized visibility of distant light. Used for compositing grids together. + */ +typedef struct LightProbeVisibilityData { + uint8_t *L0; + uint8_t *L1_a; + uint8_t *L1_b; + uint8_t *L1_c; +} LightProbeVisibilityData; + +/** + * Used to avoid light leaks. Validate visibility between each grid sample. + */ +typedef struct LightProbeConnectivityData { + /** Stores a bitmask of valid connections within a cell. */ + uint8_t *bitmask; +} LightProbeConnectivityData; + +/** + * Defines one block of data inside the grid cache data arrays. + * The block size if the same for all the blocks. + */ +typedef struct LightProbeBlockData { + /* Offset inside the level-of-detail this block starts. */ + int offset[3]; + /* Level-of-detail this block is from. */ + int level; +} LightProbeBlockData; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name LightProbeGridCache + * + * \{ */ + +typedef struct LightProbeGridCache { + /** Allow correct versioning / different types of data for the same layout. */ + int cache_type; + /** Spatial layout type of the data stored inside the data arrays. */ + int data_layout; + + char _pad0[4]; + + /** Number of samples in the highest level of detail. */ + int size[3]; + + /** Sparse or adaptive layout only: number of blocks inside data arrays. */ + int block_len; + /** Sparse or adaptive layout only: size of a block in samples. All 3 dimensions are equal. */ + int block_size; + /** Sparse or adaptive layout only: specify the blocks positions. */ + LightProbeBlockData *block_infos; + + /** Baked data. */ + LightProbeBakingData baking; + LightProbeIrradianceData irradiance; + LightProbeVisibilityData visibility; + LightProbeConnectivityData connectivity; +} LightProbeGridCache; + +/** #LightProbeGridCache.type (int) */ +enum { + /** Light cache was just created and is not yet baked. */ + LIGHTPROBE_CACHE_TYPE_NONE = 0, + /** Light cache is baked for one specific frame and capture all indirect lighting. */ + LIGHTPROBE_CACHE_TYPE_STATIC = 1, +}; + +/** #LightProbeGridCache.data_layout (int) */ +enum { + /** Simple uniform grid. Raw output from GPU. Used during the baking process. */ + LIGHTPROBE_CACHE_UNIFORM_GRID = 0, + /** Fills the space with different level of resolution. More efficient storage. */ + LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION = 1, +}; + +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index ad84ab716c0..39792807e90 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -34,6 +34,7 @@ struct FluidsimSettings; struct GeometrySet; struct Ipo; struct LightgroupMembership; +struct LightProbeGridCache; struct Material; struct Mesh; struct Object; @@ -448,6 +449,15 @@ typedef struct Object { /** Lightgroup membership information. */ struct LightgroupMembership *lightgroup; + /** Irradiance caches baked for this object (light-probes only). */ + struct LightProbeGridCache **irradiance_caches; + /** Number of caches inside `irradiance_caches`. */ + int irradiance_caches_len; + /** True if `irradiance_caches` is a reference to the evaluated object's cache. */ + char irradiance_caches_shared; + char _pad9[3]; + void *_pad10; + /** Runtime evaluation data (keep last). */ Object_Runtime runtime; } Object; -- 2.30.2 From dc9dded5d7e2026cb37de548e0e5a2ac423be1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Apr 2023 16:40:28 +0200 Subject: [PATCH 2/9] Operator: Add subset option back Add subset to limit baking to certain object sets. --- .../blender/editors/render/render_shading.cc | 106 ++++++++++++++++-- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 086e5f13f2f..f3de87fc026 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -1334,6 +1334,8 @@ enum { LIGHTCACHE_SUBSET_ALL = 0, LIGHTCACHE_SUBSET_DIRTY, LIGHTCACHE_SUBSET_CUBE, + LIGHTCACHE_SUBSET_SELECTED, + LIGHTCACHE_SUBSET_ACTIVE, }; static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) @@ -1350,6 +1352,9 @@ static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) case LIGHTCACHE_SUBSET_DIRTY: /* Leave tag untouched. */ break; + default: + BLI_assert_unreachable(); + break; } } } @@ -1496,15 +1501,80 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot) /* NOTE: New version destined to replace the old lightcache bake operator. */ +static void lightprobe_cache_bake_start(bContext *C, wmOperator *op) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + + auto is_irradiance_volume = [](Object *ob) -> bool { + return ob->type == OB_LIGHTPROBE && + static_cast(ob->data)->type == LIGHTPROBE_TYPE_GRID; + }; + + auto irradiance_volume_setup = [](Object *ob) { + std::cout << ob->id.name << std::endl; + BKE_lightprobe_grid_caches_free(ob); + BKE_lightprobe_grid_caches_create(ob); + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + }; + + int subset = RNA_enum_get(op->ptr, "subset"); + switch (subset) { + case LIGHTCACHE_SUBSET_ALL: { + std::cout << "LIGHTCACHE_SUBSET_ALL" << std::endl; + FOREACH_OBJECT_BEGIN (scene, view_layer, ob) { + if (is_irradiance_volume(ob)) { + irradiance_volume_setup(ob); + } + } + FOREACH_OBJECT_END; + break; + } + case LIGHTCACHE_SUBSET_DIRTY: { + std::cout << "LIGHTCACHE_SUBSET_DIRTY" << std::endl; + FOREACH_OBJECT_BEGIN (scene, view_layer, ob) { + if (is_irradiance_volume(ob) && ob->irradiance_caches_dirty) { + irradiance_volume_setup(ob); + } + } + FOREACH_OBJECT_END; + break; + } + case LIGHTCACHE_SUBSET_SELECTED: { + std::cout << "LIGHTCACHE_SUBSET_SELECTED" << std::endl; + uint objects_len = 0; + ObjectsInViewLayerParams parameters; + parameters.filter_fn = nullptr; + parameters.no_dup_data = true; + Object **objects = BKE_view_layer_array_selected_objects_params( + view_layer, nullptr, &objects_len, ¶meters); + for (Object *ob : blender::MutableSpan(objects, objects_len)) { + if (is_irradiance_volume(ob)) { + irradiance_volume_setup(ob); + } + } + MEM_freeN(objects); + break; + } + case LIGHTCACHE_SUBSET_ACTIVE: { + std::cout << "LIGHTCACHE_SUBSET_ACTIVE" << std::endl; + Object *active_ob = CTX_data_active_object(C); + if (is_irradiance_volume(active_ob)) { + irradiance_volume_setup(active_ob); + } + break; + } + default: + BLI_assert_unreachable(); + break; + } +} + static int lightprobe_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { Scene *scene = CTX_data_scene(C); - Object *active_ob = CTX_data_active_object(C); - BKE_lightprobe_grid_caches_free(active_ob); - BKE_lightprobe_grid_caches_create(active_ob); - - DEG_id_tag_update(&active_ob->id, ID_RECALC_COPY_ON_WRITE); + lightprobe_cache_bake_start(C, op); WM_event_add_modal_handler(C, op); @@ -1544,14 +1614,32 @@ static void lightprobe_cache_bake_cancel(bContext *C, wmOperator *op) WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); } -/* Executes blocking render. */ -static int lightprobe_cache_bake_exec(bContext * /*C*/, wmOperator * /*op*/) +/* Executes blocking bake. */ +static int lightprobe_cache_bake_exec(bContext *C, wmOperator *op) { + lightprobe_cache_bake_start(C, op); + return OPERATOR_FINISHED; } void OBJECT_OT_lightprobe_cache_bake(wmOperatorType *ot) { + static const EnumPropertyItem light_cache_subset_items[] = { + {LIGHTCACHE_SUBSET_ALL, "ALL", 0, "All Light Probes", "Bake all light probes"}, + {LIGHTCACHE_SUBSET_DIRTY, + "DIRTY", + 0, + "Dirty Only", + "Only bake light probes that are marked as dirty"}, + {LIGHTCACHE_SUBSET_SELECTED, + "SELECTED", + 0, + "Selected Only", + "Only bake selected light probes"}, + {LIGHTCACHE_SUBSET_ACTIVE, "ACTIVE", 0, "Active Only", "Only bake the active light probe"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + /* identifiers */ ot->name = "Bake Light Cache"; ot->idname = "OBJECT_OT_lightprobe_cache_bake"; @@ -1573,6 +1661,10 @@ void OBJECT_OT_lightprobe_cache_bake(wmOperatorType *ot) 0, 2000); RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + + ot->prop = RNA_def_enum( + ot->srna, "subset", light_cache_subset_items, 0, "Subset", "Subset of probes to update"); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); } /** \} */ -- 2.30.2 From 291e36ea723b92406cdfcf6f651b900ba83f1186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Apr 2023 17:54:18 +0200 Subject: [PATCH 3/9] Rename and encapsulate for clarity and avoid cluttering `Object` type --- source/blender/blenkernel/BKE_lightprobe.h | 23 +- .../blender/blenkernel/intern/lightprobe.cc | 214 +++++++++--------- source/blender/blenkernel/intern/object.cc | 30 ++- .../blender/editors/render/render_shading.cc | 17 +- .../blender/makesdna/DNA_lightprobe_types.h | 53 +++-- source/blender/makesdna/DNA_object_types.h | 12 +- 6 files changed, 172 insertions(+), 177 deletions(-) diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h index b976a986086..9ccc9f0f4fd 100644 --- a/source/blender/blenkernel/BKE_lightprobe.h +++ b/source/blender/blenkernel/BKE_lightprobe.h @@ -16,46 +16,45 @@ struct LightProbe; struct Main; struct BlendWriter; struct BlendDataReader; -struct LightProbeGridCache; +struct LightProbeObjectCache; +struct LightProbeGridCacheFrame; struct Object; void BKE_lightprobe_type_set(struct LightProbe *probe, short lightprobe_type); void *BKE_lightprobe_add(struct Main *bmain, const char *name); -void BKE_lightprobe_grid_cache_blend_write(struct BlendWriter *writer, - struct LightProbeGridCache **grid_caches, - int grid_caches_len); +void BKE_lightprobe_cache_blend_write(struct BlendWriter *writer, + struct LightProbeObjectCache *cache); -void BKE_lightprobe_grid_cache_blend_read(struct BlendDataReader *reader, - struct LightProbeGridCache **grid_caches, - int grid_caches_len); +void BKE_lightprobe_cache_blend_read(struct BlendDataReader *reader, + struct LightProbeObjectCache *cache); /** * Create a single empty irradiance grid cache. */ -struct LightProbeGridCache *BKE_lightprobe_grid_cache_create(void); +struct LightProbeGridCacheFrame *BKE_lightprobe_grid_cache_frame_create(void); /** * Free a single grid cache. */ -void BKE_lightprobe_grid_cache_free(struct LightProbeGridCache *cache); +void BKE_lightprobe_grid_cache_frame_free(struct LightProbeGridCacheFrame *cache); /** * Create the grid cache list depending on the lightprobe baking settings. * The list is left empty to be filled by the baking process. */ -void BKE_lightprobe_grid_caches_create(struct Object *object); +void BKE_lightprobe_cache_create(struct Object *object); /** * Free all irradiance grids allocated for the given object. */ -void BKE_lightprobe_grid_caches_free(struct Object *object); +void BKE_lightprobe_cache_free(struct Object *object); /** * Return the number of sample stored inside an irradiance cache. * This depends on the light cache type. */ -int64_t BKE_lightprobe_grid_cache_sample_count(const struct LightProbeGridCache *cache); +int64_t BKE_lightprobe_grid_cache_frame_sample_count(const struct LightProbeGridCacheFrame *cache); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/intern/lightprobe.cc b/source/blender/blenkernel/intern/lightprobe.cc index ee14d9bbd1e..dac4f66ca96 100644 --- a/source/blender/blenkernel/intern/lightprobe.cc +++ b/source/blender/blenkernel/intern/lightprobe.cc @@ -132,108 +132,106 @@ void *BKE_lightprobe_add(Main *bmain, const char *name) return probe; } -void BKE_lightprobe_grid_cache_blend_write(BlendWriter *writer, - LightProbeGridCache **grid_caches, - int grid_caches_len) +static void lightprobe_grid_cache_frame_blend_write(BlendWriter *writer, + const LightProbeGridCacheFrame *cache) { - blender::Span caches(grid_caches, grid_caches_len); - for (const LightProbeGridCache *cache : caches) { - if (cache == nullptr) { - continue; - } + BLO_write_struct(writer, LightProbeGridCacheFrame, cache); - BLO_write_struct(writer, LightProbeGridCache, cache); + if (cache->block_infos != nullptr) { + BLO_write_struct_array(writer, LightProbeGridCacheFrame, cache->block_len, cache->block_infos); + } - if (cache->block_infos != nullptr) { - BLO_write_struct_array(writer, LightProbeGridCache, cache->block_len, cache->block_infos); - } + int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache); - int64_t sample_count = BKE_lightprobe_grid_cache_sample_count(cache); + if (cache->irradiance.L0 != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L0); + } + if (cache->irradiance.L1_a != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_a); + } + if (cache->irradiance.L1_b != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_b); + } + if (cache->irradiance.L1_c != nullptr) { + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_c); + } - if (cache->irradiance.L0 != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L0); - } - if (cache->irradiance.L1_a != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_a); - } - if (cache->irradiance.L1_b != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_b); - } - if (cache->irradiance.L1_c != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_c); - } + if (cache->visibility.L0 != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L0); + } + if (cache->visibility.L1_a != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_a); + } + if (cache->visibility.L1_b != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_b); + } + if (cache->visibility.L1_c != nullptr) { + BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_c); + } - if (cache->visibility.L0 != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L0); - } - if (cache->visibility.L1_a != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_a); - } - if (cache->visibility.L1_b != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_b); - } - if (cache->visibility.L1_c != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_c); - } - - if (cache->connectivity.bitmask != nullptr) { - BLO_write_struct_array( - writer, LightProbeGridCache, sample_count, cache->connectivity.bitmask); - } + if (cache->connectivity.bitmask != nullptr) { + BLO_write_struct_array( + writer, LightProbeGridCacheFrame, sample_count, cache->connectivity.bitmask); } } -void BKE_lightprobe_grid_cache_blend_read(BlendDataReader *reader, - LightProbeGridCache **grid_caches, - int grid_caches_len) +static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, + LightProbeGridCacheFrame *cache) { - blender::MutableSpan caches(grid_caches, grid_caches_len); - for (LightProbeGridCache *&cache : caches) { - if (cache == nullptr) { - continue; - } + if (cache->block_infos != nullptr) { + BLO_read_data_address(reader, &cache->block_infos); + } - BLO_read_data_address(reader, &cache); + /* Baking data is not stored. */ + cache->baking.L0 = nullptr; + cache->baking.L1_a = nullptr; + cache->baking.L1_b = nullptr; + cache->baking.L1_c = nullptr; - if (cache->block_infos != nullptr) { - BLO_read_data_address(reader, &cache->block_infos); - } + if (cache->irradiance.L0 != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L0); + } + if (cache->irradiance.L1_a != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L1_a); + } + if (cache->irradiance.L1_b != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L1_b); + } + if (cache->irradiance.L1_c != nullptr) { + BLO_read_data_address(reader, &cache->irradiance.L1_c); + } - /* Baking data is not stored. */ - cache->baking.L0 = nullptr; - cache->baking.L1_a = nullptr; - cache->baking.L1_b = nullptr; - cache->baking.L1_c = nullptr; + if (cache->visibility.L0 != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L0); + } + if (cache->visibility.L1_a != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L1_a); + } + if (cache->visibility.L1_b != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L1_b); + } + if (cache->visibility.L1_c != nullptr) { + BLO_read_data_address(reader, &cache->visibility.L1_c); + } - if (cache->irradiance.L0 != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L0); - } - if (cache->irradiance.L1_a != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L1_a); - } - if (cache->irradiance.L1_b != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L1_b); - } - if (cache->irradiance.L1_c != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L1_c); - } + if (cache->connectivity.bitmask != nullptr) { + BLO_read_data_address(reader, &cache->connectivity.bitmask); + } +} - if (cache->visibility.L0 != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L0); - } - if (cache->visibility.L1_a != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L1_a); - } - if (cache->visibility.L1_b != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L1_b); - } - if (cache->visibility.L1_c != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L1_c); - } +void BKE_lightprobe_cache_blend_write(BlendWriter *writer, LightProbeObjectCache *cache) +{ + if (cache->grid_static_cache != nullptr) { + BLO_write_struct(writer, LightProbeGridCacheFrame, cache->grid_static_cache); + lightprobe_grid_cache_frame_blend_write(writer, cache->grid_static_cache); + } +} - if (cache->connectivity.bitmask != nullptr) { - BLO_read_data_address(reader, &cache->connectivity.bitmask); - } +void BKE_lightprobe_cache_blend_read(BlendDataReader *reader, LightProbeObjectCache *cache) +{ + if (cache->grid_static_cache != nullptr) { + BLO_read_data_address(reader, &cache->grid_static_cache); + lightprobe_grid_cache_frame_blend_read(reader, cache->grid_static_cache); } } @@ -245,16 +243,14 @@ template static void spherical_harmonic_free(T &data) MEM_SAFE_FREE(data.L1_c); } -LightProbeGridCache *BKE_lightprobe_grid_cache_create() +LightProbeGridCacheFrame *BKE_lightprobe_grid_cache_frame_create() { - LightProbeGridCache *cache = static_cast( - MEM_callocN(sizeof(LightProbeGridCache), "LightProbeGridCache")); - cache->cache_type = LIGHTPROBE_CACHE_TYPE_NONE; - cache->data_layout = LIGHTPROBE_CACHE_UNIFORM_GRID; + LightProbeGridCacheFrame *cache = static_cast( + MEM_callocN(sizeof(LightProbeGridCacheFrame), "LightProbeGridCacheFrame")); return cache; } -void BKE_lightprobe_grid_cache_free(LightProbeGridCache *cache) +void BKE_lightprobe_grid_cache_frame_free(LightProbeGridCacheFrame *cache) { MEM_SAFE_FREE(cache->block_infos); spherical_harmonic_free(cache->baking); @@ -265,38 +261,34 @@ void BKE_lightprobe_grid_cache_free(LightProbeGridCache *cache) MEM_SAFE_FREE(cache); } -void BKE_lightprobe_grid_caches_create(Object *object) +void BKE_lightprobe_cache_create(Object *object) { - BLI_assert(object->irradiance_caches == nullptr); + BLI_assert(object->lightprobe_cache == nullptr); - /* Single cache for now. */ - const int grid_caches_len = 1; - LightProbeGridCache **grid_caches = static_cast( - MEM_callocN(sizeof(LightProbeGridCache *) * grid_caches_len, "irradiance_caches")); - object->irradiance_caches = grid_caches; - object->irradiance_caches_len = grid_caches_len; + object->lightprobe_cache = static_cast( + MEM_callocN(sizeof(LightProbeObjectCache), "LightProbeObjectCache")); } -void BKE_lightprobe_grid_caches_free(Object *object) +void BKE_lightprobe_cache_free(Object *object) { - if (object->irradiance_caches == nullptr) { + if (object->lightprobe_cache == nullptr) { return; } - blender::MutableSpan caches(object->irradiance_caches, - object->irradiance_caches_len); - for (LightProbeGridCache *cache : caches) { - if (cache != nullptr) { - BKE_lightprobe_grid_cache_free(cache); + LightProbeObjectCache *cache = object->lightprobe_cache; + + if (cache->shared == false) { + if (cache->grid_static_cache != nullptr) { + BKE_lightprobe_grid_cache_frame_free(cache->grid_static_cache); } } - MEM_SAFE_FREE(object->irradiance_caches); - object->irradiance_caches_len = 0; + + MEM_SAFE_FREE(object->lightprobe_cache); } -int64_t BKE_lightprobe_grid_cache_sample_count(const LightProbeGridCache *cache) +int64_t BKE_lightprobe_grid_cache_frame_sample_count(const LightProbeGridCacheFrame *cache) { - if (cache->cache_type == LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION) { + if (cache->data_layout == LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION) { return cache->block_len * cube_i(cache->block_size); } /* LIGHTPROBE_CACHE_UNIFORM_GRID */ diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index e1b4afaec91..eeb259c8097 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -269,16 +269,15 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in } if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) { - /* Reference the original object data. */ - ob_dst->irradiance_caches = ob_src->irradiance_caches; - ob_dst->irradiance_caches_len = ob_src->irradiance_caches_len; - ob_dst->irradiance_caches_shared = true; + if (ob_src->lightprobe_cache) { + /* Reference the original object data. */ + ob_dst->lightprobe_cache = (LightProbeObjectCache *)MEM_dupallocN(ob_src->lightprobe_cache); + ob_dst->lightprobe_cache->shared = true; + } } else { /* Do not copy lightprobe's cache. */ - ob_dst->irradiance_caches = nullptr; - ob_dst->irradiance_caches_len = 0; - ob_dst->irradiance_caches_shared = false; + ob_dst->lightprobe_cache = nullptr; } } @@ -333,9 +332,7 @@ static void object_free_data(ID *id) MEM_SAFE_FREE(ob->lightgroup); - if (ob->irradiance_caches_shared == false) { - BKE_lightprobe_grid_caches_free(ob); - } + BKE_lightprobe_cache_free(ob); } static void library_foreach_modifiersForeachIDLink(void *user_data, @@ -615,10 +612,9 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre BLO_write_struct(writer, LightgroupMembership, ob->lightgroup); } - if (ob->irradiance_caches) { - BLO_write_pointer_array(writer, ob->irradiance_caches_len, ob->irradiance_caches); - BKE_lightprobe_grid_cache_blend_write( - writer, ob->irradiance_caches, ob->irradiance_caches_len); + if (ob->lightprobe_cache) { + BLO_write_struct(writer, LightProbeObjectCache, ob->lightprobe_cache); + BKE_lightprobe_cache_blend_write(writer, ob->lightprobe_cache); } } @@ -839,8 +835,10 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_data_address(reader, &ob->lightgroup); - BLO_read_pointer_array(reader, (void **)&ob->irradiance_caches); - BKE_lightprobe_grid_cache_blend_read(reader, ob->irradiance_caches, ob->irradiance_caches_len); + BLO_read_data_address(reader, &ob->lightprobe_cache); + if (ob->lightprobe_cache) { + BKE_lightprobe_cache_blend_read(reader, ob->lightprobe_cache); + } } /* XXX deprecated - old animation system */ diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index f3de87fc026..6f2be952fba 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -1512,16 +1512,14 @@ static void lightprobe_cache_bake_start(bContext *C, wmOperator *op) }; auto irradiance_volume_setup = [](Object *ob) { - std::cout << ob->id.name << std::endl; - BKE_lightprobe_grid_caches_free(ob); - BKE_lightprobe_grid_caches_create(ob); + BKE_lightprobe_cache_free(ob); + BKE_lightprobe_cache_create(ob); DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); }; int subset = RNA_enum_get(op->ptr, "subset"); switch (subset) { case LIGHTCACHE_SUBSET_ALL: { - std::cout << "LIGHTCACHE_SUBSET_ALL" << std::endl; FOREACH_OBJECT_BEGIN (scene, view_layer, ob) { if (is_irradiance_volume(ob)) { irradiance_volume_setup(ob); @@ -1531,9 +1529,8 @@ static void lightprobe_cache_bake_start(bContext *C, wmOperator *op) break; } case LIGHTCACHE_SUBSET_DIRTY: { - std::cout << "LIGHTCACHE_SUBSET_DIRTY" << std::endl; FOREACH_OBJECT_BEGIN (scene, view_layer, ob) { - if (is_irradiance_volume(ob) && ob->irradiance_caches_dirty) { + if (is_irradiance_volume(ob) && ob->lightprobe_cache && ob->lightprobe_cache->dirty) { irradiance_volume_setup(ob); } } @@ -1541,7 +1538,6 @@ static void lightprobe_cache_bake_start(bContext *C, wmOperator *op) break; } case LIGHTCACHE_SUBSET_SELECTED: { - std::cout << "LIGHTCACHE_SUBSET_SELECTED" << std::endl; uint objects_len = 0; ObjectsInViewLayerParams parameters; parameters.filter_fn = nullptr; @@ -1557,7 +1553,6 @@ static void lightprobe_cache_bake_start(bContext *C, wmOperator *op) break; } case LIGHTCACHE_SUBSET_ACTIVE: { - std::cout << "LIGHTCACHE_SUBSET_ACTIVE" << std::endl; Object *active_ob = CTX_data_active_object(C); if (is_irradiance_volume(active_ob)) { irradiance_volume_setup(active_ob); @@ -1722,7 +1717,7 @@ static bool lightprobe_cache_free_poll(bContext *C) { Object *object = CTX_data_active_object(C); - return object && object->irradiance_caches != nullptr; + return object && object->lightprobe_cache != nullptr; } static int lightprobe_cache_free_exec(bContext *C, wmOperator * /*op*/) @@ -1734,11 +1729,11 @@ static int lightprobe_cache_free_exec(bContext *C, wmOperator * /*op*/) wmWindowManager *wm = CTX_wm_manager(C); WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); - if (object->irradiance_caches == nullptr) { + if (object->lightprobe_cache == nullptr) { return OPERATOR_CANCELLED; } - BKE_lightprobe_grid_caches_free(object); + BKE_lightprobe_cache_free(object); DEG_id_tag_update(&object->id, ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index c9c11725c32..abc80831f9b 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -259,20 +259,18 @@ typedef struct LightProbeBlockData { /** \} */ /* -------------------------------------------------------------------- */ -/** \name LightProbeGridCache +/** \name LightProbeGridCacheFrame * * \{ */ -typedef struct LightProbeGridCache { - /** Allow correct versioning / different types of data for the same layout. */ - int cache_type; - /** Spatial layout type of the data stored inside the data arrays. */ - int data_layout; - - char _pad0[4]; - +/** + * A frame worth of baked lighting data. + */ +typedef struct LightProbeGridCacheFrame { /** Number of samples in the highest level of detail. */ int size[3]; + /** Spatial layout type of the data stored inside the data arrays. */ + int data_layout; /** Sparse or adaptive layout only: number of blocks inside data arrays. */ int block_len; @@ -286,17 +284,9 @@ typedef struct LightProbeGridCache { LightProbeIrradianceData irradiance; LightProbeVisibilityData visibility; LightProbeConnectivityData connectivity; -} LightProbeGridCache; +} LightProbeGridCacheFrame; -/** #LightProbeGridCache.type (int) */ -enum { - /** Light cache was just created and is not yet baked. */ - LIGHTPROBE_CACHE_TYPE_NONE = 0, - /** Light cache is baked for one specific frame and capture all indirect lighting. */ - LIGHTPROBE_CACHE_TYPE_STATIC = 1, -}; - -/** #LightProbeGridCache.data_layout (int) */ +/** #LightProbeGridCacheFrame.data_layout (int) */ enum { /** Simple uniform grid. Raw output from GPU. Used during the baking process. */ LIGHTPROBE_CACHE_UNIFORM_GRID = 0, @@ -304,6 +294,31 @@ enum { LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION = 1, }; +/** + * Per object container of baked data. + * Should be called #LightProbeCache but name is already taken. + */ +typedef struct LightProbeObjectCache { + /** Allow correct versioning / different types of data for the same layout. */ + int cache_type; + /** True if this cache references the original object's cache. */ + char shared; + /** True if the cache has been tagged for automatic baking. */ + char dirty; + + char _pad0[2]; + + struct LightProbeGridCacheFrame *grid_static_cache; +} LightProbeObjectCache; + +/** #LightProbeObjectCache.type (int) */ +enum { + /** Light cache was just created and is not yet baked. Keep as 0 for default value. */ + LIGHTPROBE_CACHE_TYPE_NONE = 0, + /** Light cache is baked for one specific frame and capture all indirect lighting. */ + LIGHTPROBE_CACHE_TYPE_STATIC = 1, +}; + /** \} */ #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 39792807e90..388e7e806c3 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -34,7 +34,7 @@ struct FluidsimSettings; struct GeometrySet; struct Ipo; struct LightgroupMembership; -struct LightProbeGridCache; +struct LightProbeGridCacheFrame; struct Material; struct Mesh; struct Object; @@ -450,13 +450,9 @@ typedef struct Object { struct LightgroupMembership *lightgroup; /** Irradiance caches baked for this object (light-probes only). */ - struct LightProbeGridCache **irradiance_caches; - /** Number of caches inside `irradiance_caches`. */ - int irradiance_caches_len; - /** True if `irradiance_caches` is a reference to the evaluated object's cache. */ - char irradiance_caches_shared; - char _pad9[3]; - void *_pad10; + struct LightProbeObjectCache *lightprobe_cache; + + void *_pad9; /** Runtime evaluation data (keep last). */ Object_Runtime runtime; -- 2.30.2 From 144abfd0698ebb54cec00a45e7d0e7500c357e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Apr 2023 19:21:19 +0200 Subject: [PATCH 4/9] Fix reading and doubly written struct data --- .../blender/blenkernel/intern/lightprobe.cc | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/lightprobe.cc b/source/blender/blenkernel/intern/lightprobe.cc index dac4f66ca96..2b2676b3be6 100644 --- a/source/blender/blenkernel/intern/lightprobe.cc +++ b/source/blender/blenkernel/intern/lightprobe.cc @@ -135,8 +135,6 @@ void *BKE_lightprobe_add(Main *bmain, const char *name) static void lightprobe_grid_cache_frame_blend_write(BlendWriter *writer, const LightProbeGridCacheFrame *cache) { - BLO_write_struct(writer, LightProbeGridCacheFrame, cache); - if (cache->block_infos != nullptr) { BLO_write_struct_array(writer, LightProbeGridCacheFrame, cache->block_len, cache->block_infos); } @@ -182,6 +180,8 @@ static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, BLO_read_data_address(reader, &cache->block_infos); } + int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache); + /* Baking data is not stored. */ cache->baking.L0 = nullptr; cache->baking.L1_a = nullptr; @@ -189,29 +189,29 @@ static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, cache->baking.L1_c = nullptr; if (cache->irradiance.L0 != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L0); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L0); } if (cache->irradiance.L1_a != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L1_a); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_a); } if (cache->irradiance.L1_b != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L1_b); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_b); } if (cache->irradiance.L1_c != nullptr) { - BLO_read_data_address(reader, &cache->irradiance.L1_c); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_c); } if (cache->visibility.L0 != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L0); + BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L0); } if (cache->visibility.L1_a != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L1_a); + BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L1_a); } if (cache->visibility.L1_b != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L1_b); + BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L1_b); } if (cache->visibility.L1_c != nullptr) { - BLO_read_data_address(reader, &cache->visibility.L1_c); + BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L1_c); } if (cache->connectivity.bitmask != nullptr) { -- 2.30.2 From 1f47deb86c83f8f216b366c38c2eee22764d8b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 15 Apr 2023 21:33:29 +0200 Subject: [PATCH 5/9] Add debug surfel array to LightProbeGridCacheFrame --- source/blender/blenkernel/intern/lightprobe.cc | 3 +++ source/blender/makesdna/DNA_lightprobe_types.h | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/lightprobe.cc b/source/blender/blenkernel/intern/lightprobe.cc index 2b2676b3be6..c1d7a1ed33a 100644 --- a/source/blender/blenkernel/intern/lightprobe.cc +++ b/source/blender/blenkernel/intern/lightprobe.cc @@ -187,6 +187,8 @@ static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, cache->baking.L1_a = nullptr; cache->baking.L1_b = nullptr; cache->baking.L1_c = nullptr; + cache->surfels = nullptr; + cache->surfels_len = 0; if (cache->irradiance.L0 != nullptr) { BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L0); @@ -257,6 +259,7 @@ void BKE_lightprobe_grid_cache_frame_free(LightProbeGridCacheFrame *cache) spherical_harmonic_free(cache->irradiance); spherical_harmonic_free(cache->visibility); MEM_SAFE_FREE(cache->connectivity.bitmask); + MEM_SAFE_FREE(cache->surfels); MEM_SAFE_FREE(cache); } diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index abc80831f9b..1a581a7559f 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -279,11 +279,19 @@ typedef struct LightProbeGridCacheFrame { /** Sparse or adaptive layout only: specify the blocks positions. */ LightProbeBlockData *block_infos; - /** Baked data. */ + /** In-progress baked data. Not stored in file. */ LightProbeBakingData baking; + /** Baked data. */ LightProbeIrradianceData irradiance; LightProbeVisibilityData visibility; LightProbeConnectivityData connectivity; + + char _pad[4]; + + /** Number of debug surfels. */ + int surfels_len; + /** Debug surfels used to visualize the baking process. Not stored in file. */ + void *surfels; } LightProbeGridCacheFrame; /** #LightProbeGridCacheFrame.data_layout (int) */ -- 2.30.2 From ee5256c004c30be637d4fc8ddaabdba33abfcfe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 15 Apr 2023 21:53:06 +0200 Subject: [PATCH 6/9] Fix comment about color-space --- source/blender/makesdna/DNA_lightprobe_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 1a581a7559f..a97b3d45696 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -218,7 +218,7 @@ typedef struct LightProbeBakingData { } LightProbeBakingData; /** - * Irradiance stored as RGB triple using scene referred color space. + * Irradiance stored as RGB triple using scene linear color space. */ typedef struct LightProbeIrradianceData { float (*L0)[3]; -- 2.30.2 From f58fae995f9af355d55a27b82d1bceb9c7b3beda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 15 Apr 2023 21:59:16 +0200 Subject: [PATCH 7/9] Change type of visibility storage This is the uncompressed format and the data still need to be signed. --- source/blender/makesdna/DNA_lightprobe_types.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index a97b3d45696..487a954429c 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -231,10 +231,10 @@ typedef struct LightProbeIrradianceData { * Normalized visibility of distant light. Used for compositing grids together. */ typedef struct LightProbeVisibilityData { - uint8_t *L0; - uint8_t *L1_a; - uint8_t *L1_b; - uint8_t *L1_c; + float *L0; + float *L1_a; + float *L1_b; + float *L1_c; } LightProbeVisibilityData; /** -- 2.30.2 From 12f25885ace0ba3bc62ca36d991d83ab4a7816ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 17 Apr 2023 11:12:24 +0200 Subject: [PATCH 8/9] Avoid uneeded nullptr checks --- .../blender/blenkernel/intern/lightprobe.cc | 82 +++++-------------- 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/source/blender/blenkernel/intern/lightprobe.cc b/source/blender/blenkernel/intern/lightprobe.cc index c1d7a1ed33a..23b4977a4ce 100644 --- a/source/blender/blenkernel/intern/lightprobe.cc +++ b/source/blender/blenkernel/intern/lightprobe.cc @@ -135,50 +135,28 @@ void *BKE_lightprobe_add(Main *bmain, const char *name) static void lightprobe_grid_cache_frame_blend_write(BlendWriter *writer, const LightProbeGridCacheFrame *cache) { - if (cache->block_infos != nullptr) { - BLO_write_struct_array(writer, LightProbeGridCacheFrame, cache->block_len, cache->block_infos); - } + BLO_write_struct_array(writer, LightProbeGridCacheFrame, cache->block_len, cache->block_infos); int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache); - if (cache->irradiance.L0 != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L0); - } - if (cache->irradiance.L1_a != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_a); - } - if (cache->irradiance.L1_b != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_b); - } - if (cache->irradiance.L1_c != nullptr) { - BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_c); - } + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L0); + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_a); + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_b); + BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_c); - if (cache->visibility.L0 != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L0); - } - if (cache->visibility.L1_a != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_a); - } - if (cache->visibility.L1_b != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_b); - } - if (cache->visibility.L1_c != nullptr) { - BLO_write_int8_array(writer, sample_count, (int8_t *)cache->visibility.L1_c); - } + BLO_write_float_array(writer, sample_count, cache->visibility.L0); + BLO_write_float_array(writer, sample_count, cache->visibility.L1_a); + BLO_write_float_array(writer, sample_count, cache->visibility.L1_b); + BLO_write_float_array(writer, sample_count, cache->visibility.L1_c); - if (cache->connectivity.bitmask != nullptr) { - BLO_write_struct_array( - writer, LightProbeGridCacheFrame, sample_count, cache->connectivity.bitmask); - } + BLO_write_struct_array( + writer, LightProbeGridCacheFrame, sample_count, cache->connectivity.bitmask); } static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, LightProbeGridCacheFrame *cache) { - if (cache->block_infos != nullptr) { - BLO_read_data_address(reader, &cache->block_infos); - } + BLO_read_data_address(reader, &cache->block_infos); int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache); @@ -190,35 +168,17 @@ static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, cache->surfels = nullptr; cache->surfels_len = 0; - if (cache->irradiance.L0 != nullptr) { - BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L0); - } - if (cache->irradiance.L1_a != nullptr) { - BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_a); - } - if (cache->irradiance.L1_b != nullptr) { - BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_b); - } - if (cache->irradiance.L1_c != nullptr) { - BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_c); - } + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L0); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_a); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_b); + BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_c); - if (cache->visibility.L0 != nullptr) { - BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L0); - } - if (cache->visibility.L1_a != nullptr) { - BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L1_a); - } - if (cache->visibility.L1_b != nullptr) { - BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L1_b); - } - if (cache->visibility.L1_c != nullptr) { - BLO_read_int8_array(reader, sample_count, (int8_t **)&cache->visibility.L1_c); - } + BLO_read_float_array(reader, sample_count, &cache->visibility.L0); + BLO_read_float_array(reader, sample_count, &cache->visibility.L1_a); + BLO_read_float_array(reader, sample_count, &cache->visibility.L1_b); + BLO_read_float_array(reader, sample_count, &cache->visibility.L1_c); - if (cache->connectivity.bitmask != nullptr) { - BLO_read_data_address(reader, &cache->connectivity.bitmask); - } + BLO_read_data_address(reader, &cache->connectivity.bitmask); } void BKE_lightprobe_cache_blend_write(BlendWriter *writer, LightProbeObjectCache *cache) -- 2.30.2 From e3e5f6efb4f85b320da023e0034ac1fd0e7640b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 17 Apr 2023 11:13:00 +0200 Subject: [PATCH 9/9] Avoid issue when loading a blendfile with incompatible data layout --- source/blender/blenkernel/intern/lightprobe.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/blender/blenkernel/intern/lightprobe.cc b/source/blender/blenkernel/intern/lightprobe.cc index 23b4977a4ce..48e8449dd7d 100644 --- a/source/blender/blenkernel/intern/lightprobe.cc +++ b/source/blender/blenkernel/intern/lightprobe.cc @@ -156,6 +156,14 @@ static void lightprobe_grid_cache_frame_blend_write(BlendWriter *writer, static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader, LightProbeGridCacheFrame *cache) { + if (!ELEM(cache->data_layout, + LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION, + LIGHTPROBE_CACHE_UNIFORM_GRID)) { + /* Do not try to read data from incompatible layout. Clear all pointers. */ + memset(cache, 0, sizeof(*cache)); + return; + } + BLO_read_data_address(reader, &cache->block_infos); int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache); -- 2.30.2