WIP: Geometry nodes: Basic volume simulation support #108468
|
@ -53,6 +53,8 @@ class BDataWriter {
|
|||
* \return Slice where the data has been written to.
|
||||
*/
|
||||
virtual BDataSlice write(const void *data, int64_t size) = 0;
|
||||
[[nodiscard]] virtual std::ostream &stream() = 0;
|
||||
[[nodiscard]] virtual std::string &name() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -124,6 +126,7 @@ class DiskBDataReader : public BDataReader {
|
|||
public:
|
||||
DiskBDataReader(std::string bdata_dir);
|
||||
[[nodiscard]] bool read(const BDataSlice &slice, void *r_data) const override;
|
||||
[[nodiscard]] const std::string &dir() const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -142,6 +145,8 @@ class DiskBDataWriter : public BDataWriter {
|
|||
DiskBDataWriter(std::string bdata_name, std::ostream &bdata_file, int64_t current_offset);
|
||||
|
||||
BDataSlice write(const void *data, int64_t size) override;
|
||||
[[nodiscard]] std::ostream &stream() override;
|
||||
[[nodiscard]] std::string &name() override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -157,6 +162,7 @@ std::string get_default_modifier_bake_directory(const Main &bmain,
|
|||
*/
|
||||
void serialize_modifier_simulation_state(const ModifierSimulationState &state,
|
||||
BDataWriter &bdata_writer,
|
||||
BDataWriter &vdb_writer,
|
||||
BDataSharing &bdata_sharing,
|
||||
DictionaryValue &r_io_root);
|
||||
/**
|
||||
|
|
|
@ -3,16 +3,19 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_instances.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_simulation_state_serialize.hh"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_volume_types.h"
|
||||
|
||||
#include "BLI_endian_defines.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
|
@ -23,6 +26,11 @@
|
|||
#include "RNA_access.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/io/Stream.h>
|
||||
# include <openvdb/openvdb.h>
|
||||
#endif
|
||||
|
||||
namespace blender::bke::sim {
|
||||
|
||||
/**
|
||||
|
@ -502,6 +510,41 @@ static Mesh *try_load_mesh(const DictionaryValue &io_geometry,
|
|||
return mesh;
|
||||
}
|
||||
|
||||
static Volume *try_load_volume(const DictionaryValue &io_geometry, const BDataReader &vdb_reader)
|
||||
{
|
||||
const DictionaryValue *io_volume = io_geometry.lookup_dict("volume");
|
||||
if (!io_volume) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::optional<StringRefNull> vdb_name = io_volume->lookup_str("name");
|
||||
if (!vdb_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const DiskBDataReader *disk_reader = dynamic_cast<const DiskBDataReader *>(&vdb_reader);
|
||||
|
||||
if (disk_reader == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char vdb_path[FILE_MAX];
|
||||
BLI_path_join(vdb_path, sizeof(vdb_path), disk_reader->dir().c_str(), vdb_name.value().c_str());
|
||||
|
||||
Volume *volume = static_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));
|
||||
STRNCPY(volume->filepath, vdb_path);
|
||||
|
||||
auto cancel = [&]() {
|
||||
BKE_id_free(nullptr, volume);
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
if (!BKE_volume_load(volume, G.main)) {
|
||||
return cancel();
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
static GeometrySet load_geometry(const DictionaryValue &io_geometry,
|
||||
const BDataReader &bdata_reader,
|
||||
const BDataSharing &bdata_sharing);
|
||||
|
@ -571,6 +614,7 @@ static GeometrySet load_geometry(const DictionaryValue &io_geometry,
|
|||
geometry.replace_mesh(try_load_mesh(io_geometry, bdata_reader, bdata_sharing));
|
||||
geometry.replace_pointcloud(try_load_pointcloud(io_geometry, bdata_reader, bdata_sharing));
|
||||
geometry.replace_curves(try_load_curves(io_geometry, bdata_reader, bdata_sharing));
|
||||
geometry.replace_volume(try_load_volume(io_geometry, bdata_reader));
|
||||
geometry.replace_instances(
|
||||
try_load_instances(io_geometry, bdata_reader, bdata_sharing).release());
|
||||
return geometry;
|
||||
|
@ -634,6 +678,7 @@ static std::shared_ptr<io::serialize::ArrayValue> serialize_attributes(
|
|||
|
||||
static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet &geometry,
|
||||
BDataWriter &bdata_writer,
|
||||
BDataWriter &vdb_writer,
|
||||
BDataSharing &bdata_sharing)
|
||||
{
|
||||
auto io_geometry = std::make_shared<DictionaryValue>();
|
||||
|
@ -698,6 +743,29 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
|
|||
curves.attributes(), bdata_writer, bdata_sharing, {});
|
||||
io_curves->append("attributes", io_attributes);
|
||||
}
|
||||
#ifdef WITH_OPENVDB
|
||||
if (geometry.has_volume()) {
|
||||
const Volume &volume = *geometry.get_volume_for_read();
|
||||
|
||||
openvdb::GridCPtrVec grids;
|
||||
|
||||
for (const int i : IndexRange(BKE_volume_num_grids(&volume))) {
|
||||
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(&volume, i);
|
||||
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(&volume, volume_grid);
|
||||
grids.push_back(grid);
|
||||
}
|
||||
|
||||
try {
|
||||
std::ostream &stream = vdb_writer.stream();
|
||||
openvdb::io::Stream file(stream);
|
||||
file.write(grids);
|
||||
|
||||
auto io_volume = io_geometry->append_dict("volume");
|
||||
io_volume->append_str("name", vdb_writer.name());
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (geometry.has_instances()) {
|
||||
const bke::Instances &instances = *geometry.get_instances_for_read();
|
||||
auto io_instances = io_geometry->append_dict("instances");
|
||||
|
@ -707,8 +775,8 @@ static std::shared_ptr<DictionaryValue> serialize_geometry_set(const GeometrySet
|
|||
auto io_references = io_instances->append_array("references");
|
||||
for (const bke::InstanceReference &reference : instances.references()) {
|
||||
BLI_assert(reference.type() == bke::InstanceReference::Type::GeometrySet);
|
||||
io_references->append(
|
||||
serialize_geometry_set(reference.geometry_set(), bdata_writer, bdata_sharing));
|
||||
io_references->append(serialize_geometry_set(
|
||||
reference.geometry_set(), bdata_writer, vdb_writer, bdata_sharing));
|
||||
}
|
||||
|
||||
io_instances->append("transforms",
|
||||
|
@ -787,6 +855,7 @@ static std::shared_ptr<io::serialize::Value> serialize_primitive_value(
|
|||
|
||||
void serialize_modifier_simulation_state(const ModifierSimulationState &state,
|
||||
BDataWriter &bdata_writer,
|
||||
BDataWriter &vdb_writer,
|
||||
BDataSharing &bdata_sharing,
|
||||
DictionaryValue &r_io_root)
|
||||
{
|
||||
|
@ -819,7 +888,8 @@ void serialize_modifier_simulation_state(const ModifierSimulationState &state,
|
|||
io_state_item->append_str("type", "GEOMETRY");
|
||||
|
||||
const GeometrySet &geometry = geometry_state_item->geometry;
|
||||
auto io_geometry = serialize_geometry_set(geometry, bdata_writer, bdata_sharing);
|
||||
auto io_geometry = serialize_geometry_set(
|
||||
geometry, bdata_writer, vdb_writer, bdata_sharing);
|
||||
io_state_item->append("data", io_geometry);
|
||||
}
|
||||
else if (const AttributeSimulationStateItem *attribute_state_item =
|
||||
|
@ -1056,7 +1126,8 @@ void deserialize_modifier_simulation_state(const DictionaryValue &io_root,
|
|||
io_string.value());
|
||||
}
|
||||
else if (const io::serialize::DictionaryValue *io_string =
|
||||
io_data->get()->as_dictionary_value()) {
|
||||
io_data->get()->as_dictionary_value())
|
||||
{
|
||||
const std::optional<int64_t> size = io_string->lookup_int("size");
|
||||
if (!size) {
|
||||
continue;
|
||||
|
@ -1117,6 +1188,11 @@ DiskBDataReader::DiskBDataReader(std::string bdata_dir) : bdata_dir_(std::move(b
|
|||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &DiskBDataReader::dir() const
|
||||
{
|
||||
return bdata_dir_;
|
||||
}
|
||||
|
||||
DiskBDataWriter::DiskBDataWriter(std::string bdata_name,
|
||||
std::ostream &bdata_file,
|
||||
const int64_t current_offset)
|
||||
|
@ -1132,6 +1208,16 @@ BDataSlice DiskBDataWriter::write(const void *data, const int64_t size)
|
|||
return {bdata_name_, {old_offset, size}};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::ostream &DiskBDataWriter::stream()
|
||||
{
|
||||
return bdata_file_;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string &DiskBDataWriter::name()
|
||||
{
|
||||
return bdata_name_;
|
||||
}
|
||||
|
||||
BDataSharing::~BDataSharing()
|
||||
{
|
||||
for (const ImplicitSharingInfo *sharing_info : stored_by_runtime_.keys()) {
|
||||
|
|
|
@ -309,6 +309,7 @@ static void bake_simulation_job_startjob(void *customdata,
|
|||
|
||||
const std::string bdata_file_name = frame_file_str + ".bdata";
|
||||
const std::string meta_file_name = frame_file_str + ".json";
|
||||
const std::string vdb_file_name = frame_file_str + ".vdb";
|
||||
|
||||
char bdata_path[FILE_MAX];
|
||||
BLI_path_join(bdata_path,
|
||||
|
@ -323,13 +324,23 @@ static void bake_simulation_job_startjob(void *customdata,
|
|||
"meta",
|
||||
meta_file_name.c_str());
|
||||
|
||||
char vdb_path[FILE_MAX];
|
||||
BLI_path_join(vdb_path,
|
||||
sizeof(vdb_path),
|
||||
modifier_bake_data.absolute_bake_dir.c_str(),
|
||||
"bdata",
|
||||
vdb_file_name.c_str());
|
||||
|
||||
BLI_file_ensure_parent_dir_exists(bdata_path);
|
||||
fstream bdata_file{bdata_path, std::ios::out | std::ios::binary};
|
||||
bke::sim::DiskBDataWriter bdata_writer{bdata_file_name, bdata_file, 0};
|
||||
|
||||
fstream vdb_file{vdb_path, std::ios::out | std::ios::binary};
|
||||
bke::sim::DiskBDataWriter vdb_writer{vdb_file_name, vdb_file, 0};
|
||||
|
||||
io::serialize::DictionaryValue io_root;
|
||||
bke::sim::serialize_modifier_simulation_state(
|
||||
*sim_state, bdata_writer, *modifier_bake_data.bdata_sharing, io_root);
|
||||
*sim_state, bdata_writer, vdb_writer, *modifier_bake_data.bdata_sharing, io_root);
|
||||
|
||||
BLI_file_ensure_parent_dir_exists(meta_path);
|
||||
io::serialize::write_json_file(meta_path, io_root);
|
||||
|
|
|
@ -167,7 +167,8 @@ static void cleanup_geometry_for_simulation_state(GeometrySet &main_geometry)
|
|||
geometry.keep_only_during_modify({GEO_COMPONENT_TYPE_MESH,
|
||||
GEO_COMPONENT_TYPE_CURVE,
|
||||
GEO_COMPONENT_TYPE_POINT_CLOUD,
|
||||
GEO_COMPONENT_TYPE_INSTANCES});
|
||||
GEO_COMPONENT_TYPE_INSTANCES,
|
||||
GEO_COMPONENT_TYPE_VOLUME});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -279,7 +280,8 @@ void simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_i
|
|||
GeometryComponent &component = geometry->get_component_for_write(type);
|
||||
MutableAttributeAccessor attributes = *component.attributes_for_write();
|
||||
for (const MapItem<std::string, AnonymousAttributeIDPtr> &attribute_item :
|
||||
attribute_map.items()) {
|
||||
attribute_map.items())
|
||||
{
|
||||
attributes.rename(attribute_item.key, *attribute_item.value);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
This can throw exceptions that need to be caught, see
BKE_volume_save
.