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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/volume.cc')
-rw-r--r--source/blender/blenkernel/intern/volume.cc280
1 files changed, 166 insertions, 114 deletions
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 9b5231f7d6f..c0ce57818d1 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -28,7 +28,10 @@
#include "BLI_compiler_compat.h"
#include "BLI_fileops.h"
+#include "BLI_float3.hh"
+#include "BLI_float4x4.hh"
#include "BLI_ghash.h"
+#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_math.h"
#include "BLI_path_util.h"
@@ -36,6 +39,7 @@
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
+#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -63,6 +67,10 @@ static CLG_LogRef LOG = {"bke.volume"};
#define VOLUME_FRAME_NONE INT_MAX
+using blender::float3;
+using blender::float4x4;
+using blender::IndexRange;
+
#ifdef WITH_OPENVDB
# include <atomic>
# include <list>
@@ -144,14 +152,14 @@ static struct VolumeFileCache {
blender::Map<int, openvdb::GridBase::Ptr> simplified_grids;
/* Has the grid tree been loaded? */
- bool is_loaded;
+ mutable bool is_loaded;
/* Error message if an error occurred while loading. */
std::string error_msg;
/* User counting. */
int num_metadata_users;
int num_tree_users;
/* Mutex for on-demand reading of tree. */
- std::mutex mutex;
+ mutable std::mutex mutex;
};
struct EntryHasher {
@@ -171,10 +179,6 @@ static struct VolumeFileCache {
};
/* Cache */
- VolumeFileCache()
- {
- }
-
~VolumeFileCache()
{
BLI_assert(cache.empty());
@@ -293,7 +297,7 @@ struct VolumeGrid {
}
}
- void load(const char *volume_name, const char *filepath)
+ void load(const char *volume_name, const char *filepath) const
{
/* If already loaded or not file-backed, nothing to do. */
if (is_loaded || entry == nullptr) {
@@ -335,7 +339,7 @@ struct VolumeGrid {
is_loaded = true;
}
- void unload(const char *volume_name)
+ void unload(const char *volume_name) const
{
/* Not loaded or not file-backed, nothing to do. */
if (!is_loaded || entry == nullptr) {
@@ -436,10 +440,14 @@ struct VolumeGrid {
int simplify_level = 0;
/* OpenVDB grid if it's not shared through the file cache. */
openvdb::GridBase::Ptr local_grid;
- /* Indicates if the tree has been loaded for this grid. Note that vdb.tree()
+ /**
+ * Indicates if the tree has been loaded for this grid. Note that vdb.tree()
* may actually be loaded by another user while this is false. But only after
- * calling load() and is_loaded changes to true is it safe to access. */
- bool is_loaded;
+ * calling load() and is_loaded changes to true is it safe to access.
+ *
+ * Const write access to this must be protected by `entry->mutex`.
+ */
+ mutable bool is_loaded;
};
/* Volume Grid Vector
@@ -472,14 +480,15 @@ struct VolumeGridVector : public std::list<VolumeGrid> {
metadata.reset();
}
+ /* Mutex for file loading of grids list. Const write access to the fields after this must be
+ * protected by locking with this mutex. */
+ mutable std::mutex mutex;
/* Absolute file path that grids have been loaded from. */
char filepath[FILE_MAX];
/* File loading error message. */
std::string error_msg;
/* File Metadata. */
openvdb::MetaMap::Ptr metadata;
- /* Mutex for file loading of grids list. */
- std::mutex mutex;
};
#endif
@@ -766,10 +775,10 @@ bool BKE_volume_is_loaded(const Volume *volume)
#endif
}
-bool BKE_volume_load(Volume *volume, Main *bmain)
+bool BKE_volume_load(const Volume *volume, const Main *bmain)
{
#ifdef WITH_OPENVDB
- VolumeGridVector &grids = *volume->runtime.grids;
+ const VolumeGridVector &const_grids = *volume->runtime.grids;
if (volume->runtime.frame == VOLUME_FRAME_NONE) {
/* Skip loading this frame, outside of sequence range. */
@@ -777,15 +786,19 @@ bool BKE_volume_load(Volume *volume, Main *bmain)
}
if (BKE_volume_is_loaded(volume)) {
- return grids.error_msg.empty();
+ return const_grids.error_msg.empty();
}
/* Double-checked lock. */
- std::lock_guard<std::mutex> lock(grids.mutex);
+ std::lock_guard<std::mutex> lock(const_grids.mutex);
if (BKE_volume_is_loaded(volume)) {
- return grids.error_msg.empty();
+ return const_grids.error_msg.empty();
}
+ /* Guarded by the lock, we can continue to access the grid vector,
+ * adding error messages or a new grid, etc. */
+ VolumeGridVector &grids = const_cast<VolumeGridVector &>(const_grids);
+
/* Get absolute file path at current frame. */
const char *volume_name = volume->id.name + 2;
char filepath[FILE_MAX];
@@ -850,7 +863,10 @@ void BKE_volume_unload(Volume *volume)
/* File Save */
-bool BKE_volume_save(Volume *volume, Main *bmain, ReportList *reports, const char *filepath)
+bool BKE_volume_save(const Volume *volume,
+ const Main *bmain,
+ ReportList *reports,
+ const char *filepath)
{
#ifdef WITH_OPENVDB
if (!BKE_volume_load(volume, bmain)) {
@@ -882,6 +898,32 @@ bool BKE_volume_save(Volume *volume, Main *bmain, ReportList *reports, const cha
#endif
}
+bool BKE_volume_min_max(const Volume *volume, float3 &r_min, float3 &r_max)
+{
+ bool have_minmax = false;
+#ifdef WITH_OPENVDB
+ /* TODO: if we know the volume is going to be displayed, it may be good to
+ * load it as part of dependency graph evaluation for better threading. We
+ * could also share the bounding box computation in the global volume cache. */
+ if (BKE_volume_load(const_cast<Volume *>(volume), G.main)) {
+ 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);
+ float3 grid_min;
+ float3 grid_max;
+ if (BKE_volume_grid_bounds(grid, grid_min, grid_max)) {
+ DO_MIN(grid_min, r_min);
+ DO_MAX(grid_max, r_max);
+ have_minmax = true;
+ }
+ }
+ }
+#else
+ UNUSED_VARS(volume, r_min, r_max);
+#endif
+ return have_minmax;
+}
+
BoundBox *BKE_volume_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_VOLUME);
@@ -891,41 +933,20 @@ BoundBox *BKE_volume_boundbox_get(Object *ob)
}
if (ob->runtime.bb == nullptr) {
- Volume *volume = (Volume *)ob->data;
-
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "volume boundbox");
-
- float min[3], max[3];
- bool have_minmax = false;
- INIT_MINMAX(min, max);
-
- /* TODO: if we know the volume is going to be displayed, it may be good to
- * load it as part of dependency graph evaluation for better threading. We
- * could also share the bounding box computation in the global volume cache. */
- if (BKE_volume_load(volume, G.main)) {
- const int num_grids = BKE_volume_num_grids(volume);
-
- for (int i = 0; i < num_grids; i++) {
- VolumeGrid *grid = BKE_volume_grid_get(volume, i);
- float grid_min[3], grid_max[3];
-
- BKE_volume_grid_load(volume, grid);
- if (BKE_volume_grid_bounds(grid, grid_min, grid_max)) {
- DO_MIN(grid_min, min);
- DO_MAX(grid_max, max);
- have_minmax = true;
- }
- }
- }
+ ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ }
- if (!have_minmax) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
+ const Volume *volume = (Volume *)ob->data;
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ float3 min, max;
+ INIT_MINMAX(min, max);
+ if (!BKE_volume_min_max(volume, min, max)) {
+ min = float3(-1);
+ max = float3(1);
}
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+
return ob->runtime.bb;
}
@@ -957,7 +978,7 @@ bool BKE_volume_is_points_only(const Volume *volume)
}
for (int i = 0; i < num_grids; i++) {
- VolumeGrid *grid = BKE_volume_grid_get(volume, i);
+ const VolumeGrid *grid = BKE_volume_grid_get_for_read(volume, i);
if (BKE_volume_grid_type(grid) != VOLUME_GRID_POINTS) {
return false;
}
@@ -983,13 +1004,11 @@ static void volume_update_simplify_level(Volume *volume, const Depsgraph *depsgr
#endif
}
-static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
- struct Scene *scene,
- Object *object,
- Volume *volume_input)
+static void volume_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
+ GeometrySet &geometry_set)
{
- Volume *volume = volume_input;
-
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
@@ -1010,25 +1029,10 @@ static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
continue;
}
- if (mti->modifyVolume) {
- /* Ensure we are not modifying the input. */
- if (volume == volume_input) {
- volume = BKE_volume_copy_for_eval(volume, true);
- }
-
- Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
-
- if (volume_next && volume_next != volume) {
- /* If the modifier returned a new volume, release the old one. */
- if (volume != volume_input) {
- BKE_id_free(nullptr, volume);
- }
- volume = volume_next;
- }
+ if (mti->modifyGeometrySet) {
+ mti->modifyGeometrySet(md, &mectx, &geometry_set);
}
}
-
- return volume;
}
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
@@ -1052,6 +1056,24 @@ void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
}
}
+static Volume *take_volume_ownership_from_geometry_set(GeometrySet &geometry_set)
+{
+ if (!geometry_set.has<VolumeComponent>()) {
+ return nullptr;
+ }
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ Volume *volume = volume_component.release();
+ if (volume != nullptr) {
+ /* Add back, but only as read-only non-owning component. */
+ volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
+ }
+ else {
+ /* The component was empty, we can remove it. */
+ geometry_set.remove<VolumeComponent>();
+ }
+ return volume;
+}
+
void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
{
/* Free any evaluated data and restore original data. */
@@ -1059,11 +1081,21 @@ void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Ob
/* Evaluate modifiers. */
Volume *volume = (Volume *)object->data;
- Volume *volume_eval = volume_evaluate_modifiers(depsgraph, scene, object, volume);
+ GeometrySet geometry_set;
+ geometry_set.replace_volume(volume, GeometryOwnershipType::ReadOnly);
+ volume_evaluate_modifiers(depsgraph, scene, object, geometry_set);
+
+ Volume *volume_eval = take_volume_ownership_from_geometry_set(geometry_set);
+
+ /* If the geometry set did not contain a volume, we still create an empty one. */
+ if (volume_eval == nullptr) {
+ volume_eval = BKE_volume_new_for_eval(volume);
+ }
/* Assign evaluated object. */
- const bool is_owned = (volume != volume_eval);
- BKE_object_eval_assign_data(object, &volume_eval->id, is_owned);
+ const bool eval_is_owned = (volume != volume_eval);
+ BKE_object_eval_assign_data(object, &volume_eval->id, eval_is_owned);
+ object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set));
}
void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, const char *filepath)
@@ -1144,7 +1176,23 @@ const char *BKE_volume_grids_frame_filepath(const Volume *volume)
#endif
}
-VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
+const VolumeGrid *BKE_volume_grid_get_for_read(const Volume *volume, int grid_index)
+{
+#ifdef WITH_OPENVDB
+ const VolumeGridVector &grids = *volume->runtime.grids;
+ for (const VolumeGrid &grid : grids) {
+ if (grid_index-- == 0) {
+ return &grid;
+ }
+ }
+ return nullptr;
+#else
+ UNUSED_VARS(volume, grid_index);
+ return nullptr;
+#endif
+}
+
+VolumeGrid *BKE_volume_grid_get_for_write(Volume *volume, int grid_index)
{
#ifdef WITH_OPENVDB
VolumeGridVector &grids = *volume->runtime.grids;
@@ -1160,7 +1208,7 @@ VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
#endif
}
-VolumeGrid *BKE_volume_grid_active_get(const Volume *volume)
+const VolumeGrid *BKE_volume_grid_active_get_for_read(const Volume *volume)
{
const int num_grids = BKE_volume_num_grids(volume);
if (num_grids == 0) {
@@ -1168,15 +1216,15 @@ VolumeGrid *BKE_volume_grid_active_get(const Volume *volume)
}
const int index = clamp_i(volume->active_grid, 0, num_grids - 1);
- return BKE_volume_grid_get(volume, index);
+ return BKE_volume_grid_get_for_read(volume, index);
}
/* Tries to find a grid with the given name. Make sure that that the volume has been loaded. */
-VolumeGrid *BKE_volume_grid_find(const Volume *volume, const char *name)
+const VolumeGrid *BKE_volume_grid_find_for_read(const Volume *volume, const char *name)
{
int num_grids = BKE_volume_num_grids(volume);
for (int i = 0; i < num_grids; i++) {
- VolumeGrid *grid = BKE_volume_grid_get(volume, i);
+ const VolumeGrid *grid = BKE_volume_grid_get_for_read(volume, i);
if (STREQ(BKE_volume_grid_name(grid), name)) {
return grid;
}
@@ -1187,7 +1235,7 @@ VolumeGrid *BKE_volume_grid_find(const Volume *volume, const char *name)
/* Grid Loading */
-bool BKE_volume_grid_load(const Volume *volume, VolumeGrid *grid)
+bool BKE_volume_grid_load(const Volume *volume, const VolumeGrid *grid)
{
#ifdef WITH_OPENVDB
VolumeGridVector &grids = *volume->runtime.grids;
@@ -1205,7 +1253,7 @@ bool BKE_volume_grid_load(const Volume *volume, VolumeGrid *grid)
#endif
}
-void BKE_volume_grid_unload(const Volume *volume, VolumeGrid *grid)
+void BKE_volume_grid_unload(const Volume *volume, const VolumeGrid *grid)
{
#ifdef WITH_OPENVDB
const char *volume_name = volume->id.name + 2;
@@ -1335,34 +1383,6 @@ void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4
/* Grid Tree and Voxels */
-bool BKE_volume_grid_bounds(const VolumeGrid *volume_grid, float min[3], float max[3])
-{
-#ifdef WITH_OPENVDB
- /* TODO: we can get this from grid metadata in some cases? */
- const openvdb::GridBase::Ptr grid = volume_grid->grid();
- BLI_assert(BKE_volume_grid_is_loaded(volume_grid));
-
- openvdb::CoordBBox coordbbox;
- if (!grid->baseTree().evalLeafBoundingBox(coordbbox)) {
- INIT_MINMAX(min, max);
- return false;
- }
-
- openvdb::BBoxd bbox = grid->transform().indexToWorld(coordbbox);
- min[0] = (float)bbox.min().x();
- min[1] = (float)bbox.min().y();
- min[2] = (float)bbox.min().z();
- max[0] = (float)bbox.max().x();
- max[1] = (float)bbox.max().y();
- max[2] = (float)bbox.max().z();
- return true;
-#else
- UNUSED_VARS(volume_grid);
- INIT_MINMAX(min, max);
- return false;
-#endif
-}
-
/* Volume Editing */
Volume *BKE_volume_new_for_eval(const Volume *volume_src)
@@ -1410,7 +1430,7 @@ VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType
{
#ifdef WITH_OPENVDB
VolumeGridVector &grids = *volume->runtime.grids;
- BLI_assert(BKE_volume_grid_find(volume, name) == nullptr);
+ BLI_assert(BKE_volume_grid_find_for_read(volume, name) == nullptr);
BLI_assert(type != VOLUME_GRID_UNKNOWN);
openvdb::GridBase::Ptr vdb_grid = BKE_volume_grid_type_operation(type, CreateGridOp{});
@@ -1472,13 +1492,45 @@ float BKE_volume_simplify_factor(const Depsgraph *depsgraph)
/* OpenVDB Grid Access */
#ifdef WITH_OPENVDB
+
+bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, float3 &r_min, float3 &r_max)
+{
+ /* TODO: we can get this from grid metadata in some cases? */
+ openvdb::CoordBBox coordbbox;
+ if (!grid->baseTree().evalLeafBoundingBox(coordbbox)) {
+ return false;
+ }
+
+ openvdb::BBoxd bbox = grid->transform().indexToWorld(coordbbox);
+
+ r_min = float3((float)bbox.min().x(), (float)bbox.min().y(), (float)bbox.min().z());
+ r_max = float3((float)bbox.max().x(), (float)bbox.max().y(), (float)bbox.max().z());
+
+ return true;
+}
+
+/**
+ * Return a new grid pointer with only the metadata and transform changed.
+ * This is useful for instances, where there is a separate transform on top of the original
+ * grid transform that must be applied for some operations that only take a grid argument.
+ */
+openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
+ const blender::float4x4 &transform)
+{
+ openvdb::math::Transform::Ptr grid_transform = grid->transform().copy();
+ grid_transform->postMult(openvdb::Mat4d(((float *)transform.values)));
+
+ /* Create a transformed grid. The underlying tree is shared. */
+ return grid->copyGridReplacingTransform(grid_transform);
+}
+
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_metadata(const VolumeGrid *grid)
{
return grid->grid();
}
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const Volume *volume,
- VolumeGrid *grid)
+ const VolumeGrid *grid)
{
BKE_volume_grid_load(volume, grid);
return grid->grid();