64#define VOLUME_FRAME_NONE INT_MAX
71using blender::bke::GVolumeGrid;
76# include <openvdb/openvdb.h>
77# include <openvdb/points/PointDataGrid.h>
78# include <openvdb/tools/GridTransformer.h>
85struct VolumeGridVector :
public std::list<GVolumeGrid> {
86 VolumeGridVector() : metadata(
new openvdb::MetaMap())
91 VolumeGridVector(
const VolumeGridVector &other)
92 : std::list<GVolumeGrid>(other), error_msg(other.error_msg), metadata(other.metadata)
94 memcpy(filepath, other.filepath,
sizeof(filepath));
97 bool is_loaded()
const
99 return filepath[0] !=
'\0';
104 std::list<GVolumeGrid>::clear();
116 std::string error_msg;
118 openvdb::MetaMap::Ptr metadata;
127 openvdb::initialize();
140 volume->
runtime = MEM_new<blender::bke::VolumeRuntime>(__func__);
148 std::optional<Library *> ,
155 volume_dst->
runtime = MEM_new<blender::bke::VolumeRuntime>(__func__);
163 if (volume_src->
runtime->grids) {
164 const VolumeGridVector &grids_src = *(volume_src->
runtime->grids);
165 volume_dst->
runtime->grids = MEM_new<VolumeGridVector>(__func__, grids_src);
174 if (volume_src->
runtime->bake_materials) {
175 volume_dst->
runtime->bake_materials = std::make_unique<blender::bke::bake::BakeMaterialsList>(
176 *volume_src->
runtime->bake_materials);
193 MEM_delete(volume->
runtime->grids);
194 volume->
runtime->grids =
nullptr;
196 blender::bke::volume_grid::file_cache::unload_unused();
204 for (
int i = 0;
i < volume->
totcol;
i++) {
219 function_callback(
id, &key, (
void **)&volume->
runtime->grids, 0, user_data);
258 volume->
runtime = MEM_new<blender::bke::VolumeRuntime>(__func__);
311 if (volume->
runtime->grids ==
nullptr) {
312 volume->
runtime->grids = MEM_new<VolumeGridVector>(__func__);
334 int path_frame, path_digits;
345 if (frame_duration == 0) {
349 int frame = scene_frame - frame_start + 1;
353 if (frame < 1 || frame > frame_duration) {
359 frame =
clamp_i(frame, 1, frame_duration);
363 frame = frame % frame_duration;
365 frame += frame_duration;
368 frame = frame_duration;
373 const int pingpong_duration = frame_duration * 2 - 2;
374 frame = frame % pingpong_duration;
376 frame += pingpong_duration;
379 frame = pingpong_duration;
381 if (frame > frame_duration) {
382 frame = frame_duration * 2 - frame;
389 frame += frame_offset;
395static void volume_filepath_get(
const Main *bmain,
const Volume *volume,
char r_filepath[
FILE_MAX])
400 int path_frame, path_digits;
416 return (volume->
filepath[0] ==
'\0' || volume->
runtime->grids->is_loaded());
425 const std::string base_name = ref_base_name;
429 volume->
runtime->velocity_x_grid[0] =
'\0';
430 volume->
runtime->velocity_y_grid[0] =
'\0';
431 volume->
runtime->velocity_z_grid[0] =
'\0';
436 const StringRefNull postfixes[][3] = {{
"x",
"y",
"z"}, {
".x",
".y",
".z"}, {
"_x",
"_y",
"_z"}};
440 for (
int i = 0;
i < 3;
i++) {
441 std::string post_fixed_name = ref_base_name + postfix[
i];
454 STRNCPY(volume->
runtime->velocity_x_grid, (ref_base_name + postfix[0]).c_str());
455 STRNCPY(volume->
runtime->velocity_y_grid, (ref_base_name + postfix[1]).c_str());
456 STRNCPY(volume->
runtime->velocity_z_grid, (ref_base_name + postfix[2]).c_str());
462 volume->
runtime->velocity_x_grid[0] =
'\0';
463 volume->
runtime->velocity_y_grid[0] =
'\0';
464 volume->
runtime->velocity_z_grid[0] =
'\0';
471 const VolumeGridVector &const_grids = *volume->
runtime->grids;
479 return const_grids.error_msg.empty();
483 std::lock_guard
lock(const_grids.mutex);
485 return const_grids.error_msg.empty();
490 VolumeGridVector &grids =
const_cast<VolumeGridVector &
>(const_grids);
493 const char *volume_name = volume->
id.
name + 2;
495 volume_filepath_get(bmain, volume, filepath);
497 CLOG_INFO(&
LOG,
"Volume %s: load %s", volume_name, filepath);
502 CLOG_INFO(&
LOG,
"Volume %s: %s", volume_name, grids.error_msg.c_str());
506 blender::bke::volume_grid::file_cache::GridsFromFile grids_from_file =
507 blender::bke::volume_grid::file_cache::get_all_grids_from_file(filepath, 0);
509 if (!grids_from_file.error_message.empty()) {
510 grids.error_msg = grids_from_file.error_message;
511 CLOG_INFO(&
LOG,
"Volume %s: %s", volume_name, grids.error_msg.c_str());
515 grids.metadata = std::move(grids_from_file.file_meta_data);
516 for (GVolumeGrid &volume_grid : grids_from_file.grids) {
517 grids.emplace_back(std::move(volume_grid));
521 const char *common_velocity_names[] = {
"velocity",
"vel",
"v"};
522 for (
const char *common_velocity_name : common_velocity_names) {
528 STRNCPY(grids.filepath, filepath);
530 return grids.error_msg.empty();
540 VolumeGridVector &grids = *volume->
runtime->grids;
541 if (grids.filepath[0] !=
'\0') {
542 const char *volume_name = volume->
id.
name + 2;
556 const char *filepath)
564 VolumeGridVector &grids = *volume->
runtime->grids;
565 openvdb::GridCPtrVec vdb_grids;
570 for (
const GVolumeGrid &grid : grids) {
572 vdb_grids.push_back(grid->grid_ptr(tree_tokens.
last()));
576 openvdb::io::File file(filepath);
577 file.write(vdb_grids, *grids.metadata);
580 catch (
const openvdb::IoError &
e) {
599 if (
const VolumeGridVector *grids = volume.
runtime->grids) {
600 for (
const GVolumeGrid &grid : *grids) {
601 grid->count_memory(memory);
616 std::optional<blender::Bounds<blender::float3>>
result;
619 blender::bke::VolumeTreeAccessToken tree_token;
621 BKE_volume_grid_bounds(volume_grid->grid_ptr(tree_token)));
635 VolumeGridVector &grids = *volume->
runtime->grids;
636 if (grids.metadata) {
637 openvdb::StringMetadata::ConstPtr creator =
638 grids.metadata->getMetadata<openvdb::StringMetadata>(
"creator");
640 creator = grids.metadata->getMetadata<openvdb::StringMetadata>(
"Creator");
642 return (creator && creator->str().rfind(
"Houdini", 0) == 0);
654 if (num_grids == 0) {
658 for (
int i = 0;
i < num_grids;
i++) {
677 VolumeGridVector &grids = *volume->
runtime->grids;
678 std::list<GVolumeGrid> new_grids;
679 for (
const GVolumeGrid &old_grid : grids) {
680 GVolumeGrid simple_grid = blender::bke::volume_grid::file_cache::get_grid_from_file(
681 grids.filepath, old_grid->name(), simplify_level);
683 new_grids.push_back(std::move(simple_grid));
685 grids.swap(new_grids);
711 for (; md; md = md->
next) {
732 if (frame != volume->
runtime->frame) {
734 volume->
runtime->frame = frame;
755 Volume *volume = volume_component.release();
756 if (volume !=
nullptr) {
781 if (volume_eval ==
nullptr) {
786 const bool eval_is_owned = (volume != volume_eval);
799 if (!grids->is_loaded()) {
810 MEM_delete(volume->
runtime->grids);
811 volume->
runtime->grids = grids;
842 return volume->
runtime->grids->size();
852 return volume->
runtime->grids->error_msg.c_str();
862 return volume->
runtime->grids->filepath;
872 const VolumeGridVector &grids = *volume->
runtime->grids;
873 for (
const GVolumeGrid &grid : grids) {
874 if (grid_index-- == 0) {
888 VolumeGridVector &grids = *volume->
runtime->grids;
889 for (GVolumeGrid &grid_ptr : grids) {
890 if (grid_index-- == 0) {
891 return &grid_ptr.get_for_write();
904 if (num_grids == 0) {
916 for (
int i = 0;
i < num_grids;
i++) {
929 for (
int i = 0;
i < num_grids;
i++) {
958 return reinterpret_cast<Volume *
>(
964 template<
typename Gr
idType>
typename openvdb::GridBase::Ptr
operator()()
966 if constexpr (std::is_same_v<GridType, openvdb::points::PointDataGrid>) {
970 return GridType::create();
977blender::bke::VolumeGridData *BKE_volume_grid_add_vdb(
Volume &volume,
979 openvdb::GridBase::Ptr vdb_grid)
981 VolumeGridVector &grids = *volume.
runtime->grids;
985 vdb_grid->setName(
name);
986 grids.emplace_back(GVolumeGrid(std::move(vdb_grid)));
987 return &grids.back().get_for_write();
990void BKE_volume_metadata_set(
Volume &volume, openvdb::MetaMap::Ptr metadata)
992 volume.
runtime->grids->metadata = metadata;
999 VolumeGridVector &grids = *volume->
runtime->grids;
1000 for (VolumeGridVector::iterator it = grids.begin(); it != grids.end(); it++) {
1001 if (&it->get() == grid) {
1014 VolumeGridVector &grids = *volume->
runtime->grids;
1015 grids.push_back(GVolumeGrid(&grid));
1025 return std::abs(
determinant) >= 3.0 * openvdb::math::Tolerance<double>::value();
1048 if (simplify == 0.0f) {
1073std::optional<blender::Bounds<float3>> BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid)
1076 openvdb::CoordBBox coordbbox;
1077 if (!grid->baseTree().evalLeafBoundingBox(coordbbox)) {
1078 return std::nullopt;
1081 openvdb::BBoxd index_bbox = {
1082 openvdb::BBoxd(coordbbox.min().asVec3d(), coordbbox.max().asVec3d())};
1084 index_bbox.expand(0.5);
1086 const openvdb::BBoxd bbox = grid->transform().indexToWorld(index_bbox);
1090openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
1093 openvdb::math::Transform::Ptr grid_transform = grid->transform().copy();
1094 grid_transform->postMult(openvdb::Mat4d((
float *)
transform.ptr()));
1097 return grid->copyGridReplacingTransform(grid_transform);
1104 const openvdb::math::Mat4f matrix =
transform.baseMap()->getAffineMap()->getMat4();
1108 for (
int row = 0; row < 4; row++) {
1117 openvdb::math::Mat4f matrix_openvdb;
1119 for (
int row = 0; row < 4; row++) {
1123 return openvdb::math::Transform(std::make_shared<openvdb::math::AffineMap>(matrix_openvdb));
1132template<
typename Gr
idType>
1133static typename GridType::Ptr create_grid_with_changed_resolution(
const GridType &old_grid,
1134 const float resolution_factor)
1138 openvdb::Mat4R xform;
1139 xform.setToScale(openvdb::Vec3d(resolution_factor));
1140 openvdb::tools::GridTransformer transformer{xform};
1142 typename GridType::Ptr new_grid = old_grid.copyWithNewTree();
1143 transformer.transformGrid<openvdb::tools::BoxSampler>(old_grid, *new_grid);
1144 new_grid->transform() = old_grid.transform();
1145 new_grid->transform().preScale(1.0f / resolution_factor);
1146 new_grid->transform().postTranslate(-new_grid->voxelSize() / 2.0f);
1150struct CreateGridWithChangedResolutionOp {
1151 const openvdb::GridBase &grid;
1152 const float resolution_factor;
1154 template<
typename Gr
idType>
typename openvdb::GridBase::Ptr
operator()()
1156 return create_grid_with_changed_resolution(
static_cast<const GridType &
>(grid),
1161openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution(
1163 const openvdb::GridBase &old_grid,
1164 const float resolution_factor)
1166 CreateGridWithChangedResolutionOp op{old_grid, resolution_factor};
1167 return BKE_volume_grid_type_operation(grid_type, op);
void BKE_animdata_free(ID *id, bool do_id_user)
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
void(*)(ID *id, const IDCacheKey *cache_key, void **cache_p, uint flags, void *user_data) IDTypeForeachCacheFunctionCallback
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
void * BKE_id_new(Main *bmain, short type, const char *name)
void * BKE_id_new_nomain(short type, const char *name)
void BKE_id_blend_write(BlendWriter *writer, ID *id)
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
void BKE_modifiers_clear_errors(Object *ob)
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
ModifierData * BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *data)
General operations, lookup, etc. for blender objects.
void BKE_object_eval_assign_data(Object *object, ID *data, bool is_owned)
void BKE_object_free_derived_caches(Object *ob)
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, blender::StringRefNull filepath)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void(* BKE_volume_batch_cache_dirty_tag_cb)(Volume *volume, int mode)
void(* BKE_volume_batch_cache_free_cb)(Volume *volume)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
MINLINE int clamp_i(int value, int min, int max)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool void BLI_path_frame_strip(char *path, char *r_ext, size_t ext_maxncpy) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) ATTR_NONNULL(1
bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) ATTR_NONNULL(1)
char * STRNCPY(char(&dst)[N], const char *src)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
void BLO_write_pointer_array(BlendWriter *writer, int64_t num, const void *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int64_t array_size, void **ptr_p)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLT_I18NCONTEXT_ID_VOLUME
#define CLOG_INFO(clg_ref,...)
bool DEG_is_active(const Depsgraph *depsgraph)
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
Main * DEG_get_bmain(const Depsgraph *graph)
T * DEG_get_original(T *id)
Scene * DEG_get_input_scene(const Depsgraph *graph)
#define ID_BLEND_PATH(_bmain, _id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define DNA_struct_default_get(struct_name)
Object is a sort of wrapper for general info.
@ VOLUME_SEQUENCE_PING_PONG
Read Guarded memory(de)allocation.
const blender::bke::VolumeGridData * BKE_volume_grid_active_get_for_read(const Volume *volume)
void BKE_volume_grid_add(Volume *volume, const blender::bke::VolumeGridData &grid)
#define VOLUME_FRAME_NONE
static void volume_blend_read_after_liblink(BlendLibReader *, ID *id)
bool BKE_volume_is_loaded(const Volume *volume)
void BKE_volume_batch_cache_free(Volume *volume)
bool BKE_volume_is_y_up(const Volume *volume)
int BKE_volume_num_grids(const Volume *volume)
Volume * BKE_volume_copy_for_eval(const Volume *volume_src)
bool BKE_volume_save(const Volume *volume, const Main *bmain, ReportList *reports, const char *filepath)
void BKE_volume_batch_cache_dirty_tag(Volume *volume, int mode)
bool BKE_volume_load(const Volume *volume, const Main *bmain)
blender::bke::VolumeGridData * BKE_volume_grid_get_for_write(Volume *volume, int grid_index)
bool BKE_volume_is_points_only(const Volume *volume)
static void volume_init_data(ID *id)
static void volume_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
Volume * BKE_volume_add(Main *bmain, const char *name)
static void volume_evaluate_modifiers(Depsgraph *depsgraph, Scene *scene, Object *object, blender::bke::GeometrySet &geometry_set)
std::optional< blender::Bounds< blender::float3 > > BKE_volume_min_max(const Volume *volume)
bool BKE_volume_set_velocity_grid_by_name(Volume *volume, const StringRef ref_base_name)
static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volume)
void(* BKE_volume_batch_cache_dirty_tag_cb)(Volume *volume, int mode)
bool BKE_volume_grid_determinant_valid(const double determinant)
static void volume_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Volume * BKE_volume_new_for_eval(const Volume *volume_src)
static void volume_foreach_cache(ID *id, IDTypeForeachCacheFunctionCallback function_callback, void *user_data)
void BKE_volume_grid_remove(Volume *volume, const blender::bke::VolumeGridData *grid)
int BKE_volume_simplify_level(const Depsgraph *depsgraph)
void BKE_volume_eval_geometry(Depsgraph *depsgraph, Volume *volume)
blender::bke::VolumeGridData * BKE_volume_grid_find_for_write(Volume *volume, const StringRef name)
static void volume_free_data(ID *id)
const char * BKE_volume_grids_frame_filepath(const Volume *volume)
float BKE_volume_simplify_factor(const Depsgraph *depsgraph)
static void volume_update_simplify_level(Main *bmain, Volume *volume, const Depsgraph *depsgraph)
const blender::bke::VolumeGridData * BKE_volume_grid_get(const Volume *volume, int grid_index)
void BKE_volume_unload(Volume *volume)
void(* BKE_volume_batch_cache_free_cb)(Volume *volume)
static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
static void volume_blend_read_data(BlendDataReader *reader, ID *id)
void BKE_volume_count_memory(const Volume &volume, blender::MemoryCounter &memory)
bool BKE_volume_voxel_size_valid(const float3 &voxel_size)
static void volume_foreach_id(ID *id, LibraryForeachIDData *data)
const blender::bke::VolumeGridData * BKE_volume_grid_find(const Volume *volume, const StringRef name)
bool BKE_volume_grid_transform_valid(const float4x4 &transform)
static Volume * take_volume_ownership_from_geometry_set(blender::bke::GeometrySet &geometry_set)
const char * BKE_volume_grids_error_msg(const Volume *volume)
void BKE_volume_data_update(Depsgraph *depsgraph, Scene *scene, Object *object)
void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, const char *filepath)
void BKE_volume_init_grids(Volume *volume)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
const T & last(const int64_t n=0) const
void append_as(ForwardValue &&...value)
float determinant(MatBase< C, R >) RET
void * MEM_dupallocN(const void *vmemh)
std::string get_name(const VolumeGridData &grid)
VolumeGridType get_type(const VolumeGridData &grid)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
T determinant(const MatBase< T, Size, Size > &mat)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
struct ModifierData * next
void(* modify_geometry_set)(ModifierData *md, const ModifierEvalContext *ctx, blender::bke::GeometrySet *geometry_set)
VolumeRuntimeHandle * runtime
struct PackedFile * packedfile
void replace_volume(Volume *volume, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
bool has(const GeometryComponent::Type component_type) const
void remove(const GeometryComponent::Type component_type)