Geometry Nodes: store path to simulation bake in modifier

This adds `char *simulation_bake_directory` to the nodes modifier. The path is automatically generated the first time the modifier is baked. It is _not_ automatically changed afterwards. The path is relative to the .blend file by default. For now, the path is not exposed in the UI or Python API.

This fixes issues where renaming objects/modifiers can cause the baked data to not work anymore.

Pull Request: https://projects.blender.org/blender/blender/pulls/108201
This commit is contained in:
Jacques Lucke
2023-05-24 08:45:31 +02:00
parent d56c38525c
commit edf4cb8b67
8 changed files with 96 additions and 64 deletions

View File

@@ -162,7 +162,7 @@ class ModifierSimulationCache {
CacheState cache_state_ = CacheState::Valid;
bool failed_finding_bake_ = false;
void try_discover_bake(StringRefNull meta_dir, StringRefNull bdata_dir);
void try_discover_bake(StringRefNull absolute_bake_dir);
bool has_state_at_frame(const SubFrame &frame) const;
bool has_states() const;

View File

@@ -143,12 +143,11 @@ class DiskBDataWriter : public BDataWriter {
};
/**
* Get the directory that contains all baked simulation data for the given modifier. This is a
* parent directory of the two directories below.
* Get the directory that contains all baked simulation data for the given modifier.
*/
std::string get_bake_directory(const Main &bmain, const Object &object, const ModifierData &md);
std::string get_bdata_directory(const Main &bmain, const Object &object, const ModifierData &md);
std::string get_meta_directory(const Main &bmain, const Object &object, const ModifierData &md);
std::string get_default_modifier_bake_directory(const Main &bmain,
const Object &object,
const ModifierData &md);
/**
* Encode the simulation state in a #DictionaryValue which also contains references to external

View File

@@ -37,19 +37,24 @@ StringSimulationStateItem::StringSimulationStateItem(std::string value) : value_
{
}
void ModifierSimulationCache::try_discover_bake(const StringRefNull meta_dir,
const StringRefNull bdata_dir)
void ModifierSimulationCache::try_discover_bake(const StringRefNull absolute_bake_dir)
{
if (failed_finding_bake_) {
return;
}
if (!BLI_is_dir(meta_dir.c_str()) || !BLI_is_dir(bdata_dir.c_str())) {
char meta_dir[FILE_MAX];
BLI_path_join(meta_dir, sizeof(meta_dir), absolute_bake_dir.c_str(), "meta");
char bdata_dir[FILE_MAX];
BLI_path_join(bdata_dir, sizeof(bdata_dir), absolute_bake_dir.c_str(), "bdata");
if (!BLI_is_dir(meta_dir) || !BLI_is_dir(bdata_dir)) {
failed_finding_bake_ = true;
return;
}
direntry *dir_entries = nullptr;
const int dir_entries_num = BLI_filelist_dir_contents(meta_dir.c_str(), &dir_entries);
const int dir_entries_num = BLI_filelist_dir_contents(meta_dir, &dir_entries);
BLI_SCOPED_DEFER([&]() { BLI_filelist_free(dir_entries, dir_entries_num); });
if (dir_entries_num == 0) {

View File

@@ -42,26 +42,18 @@ static std::string escape_name(const StringRef name)
return ss.str();
}
static std::string get_blendcache_directory(const Main &bmain)
static std::string get_blend_file_name(const Main &bmain)
{
StringRefNull blend_file_path = BKE_main_blendfile_path(&bmain);
char blend_directory[FILE_MAX];
const StringRefNull blend_file_path = BKE_main_blendfile_path(&bmain);
char blend_name[FILE_MAX];
BLI_path_split_dir_file(blend_file_path.c_str(),
blend_directory,
sizeof(blend_directory),
blend_name,
sizeof(blend_name));
BLI_path_split_file_part(blend_file_path.c_str(), blend_name, sizeof(blend_name));
const int64_t type_start_index = StringRef(blend_name).rfind(".");
if (type_start_index == StringRef::not_found) {
return "";
}
blend_name[type_start_index] = '\0';
const std::string blendcache_name = "blendcache_" + StringRef(blend_name);
char blendcache_dir[FILE_MAX];
BLI_path_join(blendcache_dir, sizeof(blendcache_dir), blend_directory, blendcache_name.c_str());
return blendcache_dir;
return "blendcache_" + StringRef(blend_name);
}
static std::string get_modifier_sim_name(const Object &object, const ModifierData &md)
@@ -71,29 +63,18 @@ static std::string get_modifier_sim_name(const Object &object, const ModifierDat
return "sim_" + object_name_escaped + "_" + modifier_name_escaped;
}
std::string get_bake_directory(const Main &bmain, const Object &object, const ModifierData &md)
std::string get_default_modifier_bake_directory(const Main &bmain,
const Object &object,
const ModifierData &md)
{
char bdata_dir[FILE_MAX];
BLI_path_join(bdata_dir,
sizeof(bdata_dir),
get_blendcache_directory(bmain).c_str(),
char dir[FILE_MAX];
/* Make path that's relative to the .blend file. */
BLI_path_join(dir,
sizeof(dir),
"//",
get_blend_file_name(bmain).c_str(),
get_modifier_sim_name(object, md).c_str());
return bdata_dir;
}
std::string get_bdata_directory(const Main &bmain, const Object &object, const ModifierData &md)
{
char bdata_dir[FILE_MAX];
BLI_path_join(
bdata_dir, sizeof(bdata_dir), get_bake_directory(bmain, object, md).c_str(), "bdata");
return bdata_dir;
}
std::string get_meta_directory(const Main &bmain, const Object &object, const ModifierData &md)
{
char meta_dir[FILE_MAX];
BLI_path_join(meta_dir, sizeof(meta_dir), get_bake_directory(bmain, object, md).c_str(), "meta");
return meta_dir;
return dir;
}
std::shared_ptr<DictionaryValue> BDataSlice::serialize() const

View File

@@ -67,6 +67,7 @@
#include "BKE_modifier.h"
#include "BKE_node.hh"
#include "BKE_screen.h"
#include "BKE_simulation_state_serialize.hh"
#include "BKE_workspace.h"
#include "RNA_access.h"
@@ -4483,5 +4484,21 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
/* Keep this block, even when empty. */
BKE_animdata_main_cb(bmain, version_liboverride_nla_frame_start_end, NULL);
/* Store simulation bake directory in geometry nodes modifier. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
}
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->simulation_bake_directory) {
continue;
}
const std::string bake_dir = blender::bke::sim::get_default_modifier_bake_directory(
*bmain, *ob, *md);
nmd->simulation_bake_directory = BLI_strdup(bake_dir.c_str());
}
}
}
}

View File

@@ -209,8 +209,7 @@ static bool bake_simulation_poll(bContext *C)
struct ModifierBakeData {
NodesModifierData *nmd;
std::string meta_dir;
std::string bdata_dir;
std::string absolute_bake_dir;
std::unique_ptr<bke::sim::BDataSharing> bdata_sharing;
};
@@ -244,6 +243,9 @@ static void bake_simulation_job_startjob(void *customdata,
if (!BKE_id_is_editable(job.bmain, &object->id)) {
continue;
}
const char *base_path = ID_BLEND_PATH(job.bmain, &object->id);
ObjectBakeData bake_data;
bake_data.object = object;
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
@@ -252,10 +254,14 @@ static void bake_simulation_job_startjob(void *customdata,
if (nmd->simulation_cache != nullptr) {
nmd->simulation_cache->reset();
}
bake_data.modifiers.append({nmd,
bke::sim::get_meta_directory(*job.bmain, *object, *md),
bke::sim::get_bdata_directory(*job.bmain, *object, *md),
std::make_unique<BDataSharing>()});
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
nmd->simulation_bake_directory = BLI_strdup(
bke::sim::get_default_modifier_bake_directory(*job.bmain, *object, *md).c_str());
}
char absolute_bake_dir[FILE_MAX];
STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory);
BLI_path_abs(absolute_bake_dir, base_path);
bake_data.modifiers.append({nmd, absolute_bake_dir, std::make_unique<BDataSharing>()});
}
}
objects_to_bake.append(std::move(bake_data));
@@ -305,12 +311,14 @@ static void bake_simulation_job_startjob(void *customdata,
char bdata_path[FILE_MAX];
BLI_path_join(bdata_path,
sizeof(bdata_path),
modifier_bake_data.bdata_dir.c_str(),
modifier_bake_data.absolute_bake_dir.c_str(),
"bdata",
bdata_file_name.c_str());
char meta_path[FILE_MAX];
BLI_path_join(meta_path,
sizeof(meta_path),
modifier_bake_data.meta_dir.c_str(),
modifier_bake_data.absolute_bake_dir.c_str(),
"meta",
meta_file_name.c_str());
BLI_file_ensure_parent_dir_exists(bdata_path);
@@ -429,21 +437,25 @@ static int delete_baked_simulation_exec(bContext *C, wmOperator *op)
}
for (Object *object : objects) {
const char *base_path = ID_BLEND_PATH(bmain, &object->id);
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Nodes) {
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
const std::string bake_directory = bke::sim::get_bake_directory(*bmain, *object, *md);
if (BLI_exists(bake_directory.c_str())) {
if (BLI_delete(bake_directory.c_str(), true, true)) {
BKE_reportf(op->reports,
RPT_ERROR,
"Failed to remove bake directory %s",
bake_directory.c_str());
}
}
if (nmd->simulation_cache != nullptr) {
nmd->simulation_cache->reset();
}
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
continue;
}
char absolute_bake_dir[FILE_MAX];
STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory);
BLI_path_abs(absolute_bake_dir, base_path);
if (BLI_exists(absolute_bake_dir)) {
if (BLI_delete(absolute_bake_dir, true, true)) {
BKE_reportf(
op->reports, RPT_ERROR, "Failed to remove bake directory %s", absolute_bake_dir);
}
}
}
}

View File

@@ -2319,6 +2319,11 @@ typedef struct NodesModifierData {
ModifierData modifier;
struct bNodeTree *node_group;
struct NodesModifierSettings settings;
/**
* Directory where baked simulation states are stored. This may be relative to the .blend file.
*/
char *simulation_bake_directory;
void *_pad;
/**
* Contains logged information from the last evaluation.

View File

@@ -15,6 +15,7 @@
#include "BLI_listbase.h"
#include "BLI_math_vector_types.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_path_util.h"
#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_string_search.h"
@@ -1152,9 +1153,14 @@ static void prepare_simulation_states_for_evaluation(const NodesModifierData &nm
if (nmd_orig.simulation_cache->cache_state() != bke::sim::CacheState::Baked &&
!bmain_path.is_empty())
{
nmd_orig.simulation_cache->try_discover_bake(
bke::sim::get_meta_directory(*bmain, *ctx.object, nmd.modifier),
bke::sim::get_bdata_directory(*bmain, *ctx.object, nmd.modifier));
if (!StringRef(nmd.simulation_bake_directory).is_empty()) {
if (const char *base_path = ID_BLEND_PATH(bmain, &ctx.object->id)) {
char absolute_bake_dir[FILE_MAX];
STRNCPY(absolute_bake_dir, nmd.simulation_bake_directory);
BLI_path_abs(absolute_bake_dir, base_path);
nmd_orig.simulation_cache->try_discover_bake(absolute_bake_dir);
}
}
}
}
@@ -1995,6 +2001,8 @@ static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const Modif
BLO_write_struct(writer, NodesModifierData, nmd);
BLO_write_string(writer, nmd->simulation_bake_directory);
if (nmd->settings.properties != nullptr) {
Map<IDProperty *, IDPropertyUIDataBool *> boolean_props;
if (!BLO_write_is_undo(writer)) {
@@ -2033,6 +2041,7 @@ static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const Modif
static void blendRead(BlendDataReader *reader, ModifierData *md)
{
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
BLO_read_data_address(reader, &nmd->simulation_bake_directory);
if (nmd->node_group == nullptr) {
nmd->settings.properties = nullptr;
}
@@ -2053,6 +2062,9 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
tnmd->runtime_eval_log = nullptr;
tnmd->simulation_cache = nullptr;
tnmd->simulation_bake_directory = nmd->simulation_bake_directory ?
BLI_strdup(nmd->simulation_bake_directory) :
nullptr;
if (nmd->settings.properties != nullptr) {
tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag);
@@ -2068,6 +2080,7 @@ static void freeData(ModifierData *md)
}
MEM_delete(nmd->simulation_cache);
MEM_SAFE_FREE(nmd->simulation_bake_directory);
clear_runtime_data(nmd);
}