diff options
-rw-r--r-- | source/blender/blenkernel/BKE_volume.h | 20 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_volume_render.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/volume.cc | 168 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/volume_render.cc | 54 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_volume.c | 18 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_volume_types.h | 4 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_mesh_to_volume.cc | 21 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_volume_displace.cc | 2 |
8 files changed, 186 insertions, 102 deletions
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h index 2a272d06986..12c37ec56e0 100644 --- a/source/blender/blenkernel/BKE_volume.h +++ b/source/blender/blenkernel/BKE_volume.h @@ -140,6 +140,10 @@ struct VolumeGrid *BKE_volume_grid_add(struct Volume *volume, VolumeGridType type); void BKE_volume_grid_remove(struct Volume *volume, struct VolumeGrid *grid); +/* Simplify */ +int BKE_volume_simplify_level(const struct Depsgraph *depsgraph); +float BKE_volume_simplify_factor(const struct Depsgraph *depsgraph); + /* File Save */ bool BKE_volume_save(struct Volume *volume, struct Main *bmain, @@ -166,16 +170,7 @@ openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *vo struct VolumeGrid *grid, const bool clear); -template<typename GridType> -typename GridType::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *volume, - struct VolumeGrid *grid, - const bool clear) -{ - openvdb::GridBase::Ptr openvdb_grid = BKE_volume_grid_openvdb_for_write(volume, grid, clear); - BLI_assert(openvdb_grid->isType<GridType>()); - typename GridType::Ptr typed_openvdb_grid = openvdb::gridPtrCast<GridType>(openvdb_grid); - return typed_openvdb_grid; -} +VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr &grid); template<typename OpType> auto BKE_volume_grid_type_operation(const VolumeGridType grid_type, OpType &&op) @@ -212,4 +207,9 @@ auto BKE_volume_grid_type_operation(const VolumeGridType grid_type, OpType &&op) return op.template operator()<openvdb::FloatGrid>(); } +openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution( + const VolumeGridType grid_type, + const openvdb::GridBase &old_grid, + const float resolution_factor); + #endif diff --git a/source/blender/blenkernel/BKE_volume_render.h b/source/blender/blenkernel/BKE_volume_render.h index 815374105f5..d7553ccb10b 100644 --- a/source/blender/blenkernel/BKE_volume_render.h +++ b/source/blender/blenkernel/BKE_volume_render.h @@ -44,7 +44,6 @@ typedef struct DenseFloatVolumeGrid { bool BKE_volume_grid_dense_floats(const struct Volume *volume, struct VolumeGrid *volume_grid, - const float resolution_factor, DenseFloatVolumeGrid *r_dense_grid); void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid); diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 32f6a94aa7f..64d053c0e30 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -29,6 +29,7 @@ #include "BLI_compiler_compat.h" #include "BLI_fileops.h" #include "BLI_ghash.h" +#include "BLI_map.hh" #include "BLI_math.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -70,6 +71,7 @@ static CLG_LogRef LOG = {"bke.volume"}; # include <openvdb/openvdb.h> # include <openvdb/points/PointDataGrid.h> +# include <openvdb/tools/GridTransformer.h> /* Global Volume File Cache * @@ -115,12 +117,32 @@ static struct VolumeFileCache { { } + /* Returns the original grid or a simplified version depending on the given #simplify_level. */ + openvdb::GridBase::Ptr simplified_grid(const int simplify_level) + { + BLI_assert(simplify_level >= 0); + if (simplify_level == 0 || !is_loaded) { + return grid; + } + + std::lock_guard<std::mutex> lock(mutex); + return simplified_grids.lookup_or_add_cb(simplify_level, [&]() { + const float resolution_factor = 1.0f / (1 << simplify_level); + const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid); + return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor); + }); + } + /* Unique key: filename + grid name. */ std::string filepath; std::string grid_name; /* OpenVDB grid. */ openvdb::GridBase::Ptr grid; + + /* Simplified versions of #grid. The integer key is the simplification level. */ + blender::Map<int, openvdb::GridBase::Ptr> simplified_grids; + /* Has the grid tree been loaded? */ bool is_loaded; /* Error message if an error occured during loading. */ @@ -224,6 +246,7 @@ static struct VolumeFileCache { /* Note we replace the grid rather than clearing, so that if there is * any other shared pointer to the grid it will keep the tree. */ entry.grid = entry.grid->copyGridWithNewTree(); + entry.simplified_grids.clear(); entry.is_loaded = false; } } @@ -241,7 +264,8 @@ static struct VolumeFileCache { * stored in the global cache. Procedurally generated grids are not. */ struct VolumeGrid { - VolumeGrid(const VolumeFileCache::Entry &template_entry) : entry(NULL), is_loaded(false) + VolumeGrid(const VolumeFileCache::Entry &template_entry, const int simplify_level) + : entry(NULL), simplify_level(simplify_level), is_loaded(false) { entry = GLOBAL_CACHE.add_metadata_user(template_entry); } @@ -251,7 +275,10 @@ struct VolumeGrid { } VolumeGrid(const VolumeGrid &other) - : entry(other.entry), local_grid(other.local_grid), is_loaded(other.is_loaded) + : entry(other.entry), + simplify_level(other.simplify_level), + local_grid(other.local_grid), + is_loaded(other.is_loaded) { if (entry) { GLOBAL_CACHE.copy_user(*entry, is_loaded); @@ -360,8 +387,8 @@ struct VolumeGrid { { /* Don't use vdb.getName() since it copies the string, we want a pointer to the * original so it doesn't get freed out of scope. */ - openvdb::StringMetadata::ConstPtr name_meta = grid()->getMetadata<openvdb::StringMetadata>( - openvdb::GridBase::META_GRID_NAME); + openvdb::StringMetadata::ConstPtr name_meta = + main_grid()->getMetadata<openvdb::StringMetadata>(openvdb::GridBase::META_GRID_NAME); return (name_meta) ? name_meta->value().c_str() : ""; } @@ -379,7 +406,22 @@ struct VolumeGrid { return is_loaded; } - const openvdb::GridBase::Ptr &grid() const + openvdb::GridBase::Ptr grid() const + { + if (entry) { + return entry->simplified_grid(simplify_level); + } + return local_grid; + } + + void set_simplify_level(const int simplify_level) + { + BLI_assert(simplify_level >= 0); + this->simplify_level = simplify_level; + } + + private: + const openvdb::GridBase::Ptr &main_grid() const { return (entry) ? entry->grid : local_grid; } @@ -388,6 +430,9 @@ struct VolumeGrid { /* File cache entry when grid comes directly from a file and may be shared * with other volume datablocks. */ VolumeFileCache::Entry *entry; + /* If this volume grid is in the global file cache, we can reference a simplified version of it, + * instead of the original high resolution grid. */ + 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() @@ -761,7 +806,7 @@ bool BKE_volume_load(Volume *volume, Main *bmain) for (const openvdb::GridBase::Ptr &vdb_grid : vdb_grids) { if (vdb_grid) { VolumeFileCache::Entry template_entry(grids.filepath, vdb_grid); - grids.emplace_back(template_entry); + grids.emplace_back(template_entry, volume->runtime.default_simplify_level); } } @@ -906,6 +951,17 @@ bool BKE_volume_is_points_only(const Volume *volume) /* Dependency Graph */ +static void volume_update_simplify_level(Volume *volume, const Depsgraph *depsgraph) +{ + const int simplify_level = BKE_volume_simplify_level(depsgraph); + if (volume->runtime.grids) { + for (VolumeGrid &grid : *volume->runtime.grids) { + grid.set_simplify_level(simplify_level); + } + } + volume->runtime.default_simplify_level = simplify_level; +} + static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph, struct Scene *scene, Object *object, @@ -956,6 +1012,8 @@ static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph, void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume) { + volume_update_simplify_level(volume, depsgraph); + /* TODO: can we avoid modifier re-evaluation when frame did not change? */ int frame = volume_sequence_frame(depsgraph, volume); if (frame != volume->runtime.frame) { @@ -1157,11 +1215,9 @@ const char *BKE_volume_grid_name(const VolumeGrid *volume_grid) #endif } -VolumeGridType BKE_volume_grid_type(const VolumeGrid *volume_grid) -{ #ifdef WITH_OPENVDB - const openvdb::GridBase::Ptr &grid = volume_grid->grid(); - +VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr &grid) +{ if (grid->isType<openvdb::FloatGrid>()) { return VOLUME_GRID_FLOAT; } @@ -1195,10 +1251,16 @@ VolumeGridType BKE_volume_grid_type(const VolumeGrid *volume_grid) if (grid->isType<openvdb::points::PointDataGrid>()) { return VOLUME_GRID_POINTS; } -#else - UNUSED_VARS(volume_grid); + return VOLUME_GRID_UNKNOWN; +} #endif +VolumeGridType BKE_volume_grid_type(const VolumeGrid *volume_grid) +{ +#ifdef WITH_OPENVDB + const openvdb::GridBase::Ptr grid = volume_grid->grid(); + return BKE_volume_grid_type_openvdb(grid); +#endif return VOLUME_GRID_UNKNOWN; } @@ -1229,7 +1291,7 @@ int BKE_volume_grid_channels(const VolumeGrid *grid) void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4][4]) { #ifdef WITH_OPENVDB - const openvdb::GridBase::Ptr &grid = volume_grid->grid(); + const openvdb::GridBase::Ptr grid = volume_grid->grid(); const openvdb::math::Transform &transform = grid->transform(); /* Perspective not supported for now, getAffineMap() will leave out the @@ -1253,7 +1315,7 @@ bool BKE_volume_grid_bounds(const VolumeGrid *volume_grid, float min[3], float m { #ifdef WITH_OPENVDB /* TODO: we can get this from grid metadata in some cases? */ - const openvdb::GridBase::Ptr &grid = volume_grid->grid(); + const openvdb::GridBase::Ptr grid = volume_grid->grid(); BLI_assert(BKE_volume_grid_is_loaded(volume_grid)); openvdb::CoordBBox coordbbox; @@ -1302,7 +1364,6 @@ Volume *BKE_volume_copy_for_eval(Volume *volume_src, bool reference) } Volume *result = (Volume *)BKE_id_copy_ex(NULL, &volume_src->id, NULL, flags); - result->filepath[0] = '\0'; return result; } @@ -1357,6 +1418,33 @@ void BKE_volume_grid_remove(Volume *volume, VolumeGrid *grid) #endif } +int BKE_volume_simplify_level(const Depsgraph *depsgraph) +{ + if (DEG_get_mode(depsgraph) != DAG_EVAL_RENDER) { + const Scene *scene = DEG_get_input_scene(depsgraph); + if (scene->r.mode & R_SIMPLIFY) { + const float simplify = scene->r.simplify_volumes; + if (simplify == 0.0f) { + /* log2 is not defined at 0.0f, so just use some high simplify level. */ + return 16; + } + return ceilf(-log2(simplify)); + } + } + return 0; +} + +float BKE_volume_simplify_factor(const Depsgraph *depsgraph) +{ + if (DEG_get_mode(depsgraph) != DAG_EVAL_RENDER) { + const Scene *scene = DEG_get_input_scene(depsgraph); + if (scene->r.mode & R_SIMPLIFY) { + return scene->r.simplify_volumes; + } + } + return 1.0f; +} + /* OpenVDB Grid Access */ #ifdef WITH_OPENVDB @@ -1387,4 +1475,54 @@ openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const Volume *volume, return grid->grid(); } + +/* Changing the resolution of a grid. */ + +/** + * Returns a grid of the same type as the input, but with more/less resolution. If + * resolution_factor is 1/2, the resolution on each axis is halved. The transform of the returned + * grid is adjusted to match the original grid. */ +template<typename GridType> +static typename GridType::Ptr create_grid_with_changed_resolution(const GridType &old_grid, + const float resolution_factor) +{ + BLI_assert(resolution_factor > 0.0f); + + openvdb::Mat4R xform; + xform.setToScale(openvdb::Vec3d(resolution_factor)); + openvdb::tools::GridTransformer transformer{xform}; + + typename GridType::Ptr new_grid = old_grid.copyWithNewTree(); + transformer.transformGrid<openvdb::tools::BoxSampler>(old_grid, *new_grid); + new_grid->transform() = old_grid.transform(); + new_grid->transform().preScale(1.0f / resolution_factor); + new_grid->transform().postTranslate(-new_grid->voxelSize() / 2.0f); + return new_grid; +} + +struct CreateGridWithChangedResolutionOp { + const openvdb::GridBase &grid; + const float resolution_factor; + + template<typename GridType> typename openvdb::GridBase::Ptr operator()() + { + if constexpr (std::is_same_v<GridType, openvdb::StringGrid>) { + return {}; + } + else { + return create_grid_with_changed_resolution(static_cast<const GridType &>(grid), + resolution_factor); + } + } +}; + +openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution( + const VolumeGridType grid_type, + const openvdb::GridBase &old_grid, + const float resolution_factor) +{ + CreateGridWithChangedResolutionOp op{old_grid, resolution_factor}; + return BKE_volume_grid_type_operation(grid_type, op); +} + #endif diff --git a/source/blender/blenkernel/intern/volume_render.cc b/source/blender/blenkernel/intern/volume_render.cc index 8e8cfb5945a..37b397a9c6d 100644 --- a/source/blender/blenkernel/intern/volume_render.cc +++ b/source/blender/blenkernel/intern/volume_render.cc @@ -34,59 +34,12 @@ #ifdef WITH_OPENVDB # include <openvdb/openvdb.h> # include <openvdb/tools/Dense.h> -# include <openvdb/tools/GridTransformer.h> #endif /* Dense Voxels */ #ifdef WITH_OPENVDB -/** - * Returns a grid of the same type as the input, but with more/less resolution. If - * resolution_factor is 1/2, the resolution on each axis is halved. The transform of the returned - * grid is adjusted to match the original grid. */ -template<typename GridType> -static typename GridType::Ptr create_grid_with_changed_resolution(const GridType &old_grid, - const float resolution_factor) -{ - BLI_assert(resolution_factor > 0.0f); - - openvdb::Mat4R xform; - xform.setToScale(openvdb::Vec3d(resolution_factor)); - openvdb::tools::GridTransformer transformer{xform}; - - typename GridType::Ptr new_grid = GridType::create(); - transformer.transformGrid<openvdb::tools::BoxSampler>(old_grid, *new_grid); - new_grid->transform() = old_grid.transform(); - new_grid->transform().preScale(1.0f / resolution_factor); - return new_grid; -} - -struct CreateGridWithChangedResolutionOp { - const openvdb::GridBase &grid; - const float resolution_factor; - - template<typename GridType> typename openvdb::GridBase::Ptr operator()() - { - if constexpr (std::is_same_v<GridType, openvdb::StringGrid>) { - return {}; - } - else { - return create_grid_with_changed_resolution(static_cast<const GridType &>(grid), - resolution_factor); - } - } -}; - -static openvdb::GridBase::Ptr create_grid_with_changed_resolution( - const VolumeGridType grid_type, - const openvdb::GridBase &old_grid, - const float resolution_factor) -{ - CreateGridWithChangedResolutionOp op{old_grid, resolution_factor}; - return BKE_volume_grid_type_operation(grid_type, op); -} - template<typename GridType, typename VoxelType> static void extract_dense_voxels(const openvdb::GridBase &grid, const openvdb::CoordBBox bbox, @@ -152,16 +105,11 @@ static void create_texture_to_object_matrix(const openvdb::Mat4d &grid_transform bool BKE_volume_grid_dense_floats(const Volume *volume, VolumeGrid *volume_grid, - const float resolution_factor, DenseFloatVolumeGrid *r_dense_grid) { #ifdef WITH_OPENVDB const VolumeGridType grid_type = BKE_volume_grid_type(volume_grid); - openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); - if (resolution_factor != 1.0f) { - grid = create_grid_with_changed_resolution(grid_type, *grid, resolution_factor); - } const openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox(); if (bbox.empty()) { @@ -189,7 +137,7 @@ bool BKE_volume_grid_dense_floats(const Volume *volume, copy_v3_v3_int(r_dense_grid->resolution, resolution.asV()); return true; #endif - UNUSED_VARS(volume, volume_grid, resolution_factor, r_dense_grid); + UNUSED_VARS(volume, volume_grid, r_dense_grid); return false; } diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.c index 10bacadb199..1a9e40fb03b 100644 --- a/source/blender/draw/intern/draw_cache_impl_volume.c +++ b/source/blender/draw/intern/draw_cache_impl_volume.c @@ -262,8 +262,6 @@ static DRWVolumeGrid *volume_grid_cache_get(Volume *volume, VolumeGrid *grid, VolumeBatchCache *cache) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char *name = BKE_volume_grid_name(grid); /* Return cached grid. */ @@ -289,22 +287,12 @@ static DRWVolumeGrid *volume_grid_cache_get(Volume *volume, return cache_grid; } - /* Load grid tree into memory, if not loaded already. */ + /* Remember if grid was loaded. If it was not, we want to unload it after the GPUTexture has been + * created. */ const bool was_loaded = BKE_volume_grid_is_loaded(grid); - BKE_volume_grid_load(volume, grid); - - float resolution_factor = 1.0f; - if (DEG_get_mode(draw_ctx->depsgraph) != DAG_EVAL_RENDER) { - if (draw_ctx->scene->r.mode & R_SIMPLIFY) { - resolution_factor = draw_ctx->scene->r.simplify_volumes; - } - } - if (resolution_factor == 0.0f) { - return cache_grid; - } DenseFloatVolumeGrid dense_grid; - if (BKE_volume_grid_dense_floats(volume, grid, resolution_factor, &dense_grid)) { + if (BKE_volume_grid_dense_floats(volume, grid, &dense_grid)) { copy_m4_m4(cache_grid->texture_to_object, dense_grid.texture_to_object); invert_m4_m4(cache_grid->object_to_texture, dense_grid.texture_to_object); diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h index bbd23298aea..d6a3cdf04bf 100644 --- a/source/blender/makesdna/DNA_volume_types.h +++ b/source/blender/makesdna/DNA_volume_types.h @@ -31,7 +31,9 @@ typedef struct Volume_Runtime { /* Current frame in sequence for evaluated volume */ int frame; - int _pad; + + /* Default simplify level for volume grids loaded from files. */ + int default_simplify_level; } Volume_Runtime; typedef struct VolumeDisplay { diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index 508c84c3e8f..2e45ac66cff 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -33,7 +33,7 @@ #include "DNA_screen_types.h" #include "DNA_volume_types.h" -#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph.h" #include "UI_interface.h" #include "UI_resources.h" @@ -176,12 +176,19 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_MeshToVolume, panel_draw); } -static float compute_voxel_size(const MeshToVolumeModifierData *mvmd, +static float compute_voxel_size(const ModifierEvalContext *ctx, + const MeshToVolumeModifierData *mvmd, const blender::float4x4 &transform) { using namespace blender; + + float volume_simplify = BKE_volume_simplify_factor(ctx->depsgraph); + if (volume_simplify == 0.0f) { + return 0.0f; + } + if (mvmd->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) { - return mvmd->voxel_size; + return mvmd->voxel_size / volume_simplify; } if (mvmd->voxel_amount <= 0) { return 0; @@ -192,7 +199,7 @@ static float compute_voxel_size(const MeshToVolumeModifierData *mvmd, const float diagonal = float3::distance(transform * float3(bb->vec[6]), transform * float3(bb->vec[0])); const float approximate_volume_side_length = diagonal + mvmd->exterior_band_width * 2.0f; - const float voxel_size = approximate_volume_side_length / mvmd->voxel_amount; + const float voxel_size = approximate_volume_side_length / mvmd->voxel_amount / volume_simplify; return voxel_size; } @@ -215,7 +222,7 @@ static Volume *modifyVolume(ModifierData *md, const ModifierEvalContext *ctx, Vo const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) * float4x4(object_to_convert->obmat); - const float voxel_size = compute_voxel_size(mvmd, mesh_to_own_object_space_transform); + const float voxel_size = compute_voxel_size(ctx, mvmd, mesh_to_own_object_space_transform); if (voxel_size == 0.0f) { return input_volume; } @@ -246,8 +253,8 @@ static Volume *modifyVolume(ModifierData *md, const ModifierEvalContext *ctx, Vo /* Create a new volume object and add the density grid. */ Volume *volume = BKE_volume_new_for_eval(input_volume); VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT); - openvdb::FloatGrid::Ptr density_grid = BKE_volume_grid_openvdb_for_write<openvdb::FloatGrid>( - volume, c_density_grid, false); + openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>( + BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false)); /* Merge the generated grid into the density grid. Should be cheap because density_grid has just * been created as well. */ diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index 18ecefda881..22bf5cd4893 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -33,6 +33,7 @@ #include "DNA_volume_types.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "UI_interface.h" #include "UI_resources.h" @@ -290,6 +291,7 @@ static Volume *modifyVolume(ModifierData *md, const ModifierEvalContext *ctx, Vo VolumeDisplaceModifierData *vdmd = reinterpret_cast<VolumeDisplaceModifierData *>(md); /* Iterate over all grids and displace them one by one. */ + BKE_volume_load(volume, DEG_get_bmain(ctx->depsgraph)); const int grid_amount = BKE_volume_num_grids(volume); for (int grid_index = 0; grid_index < grid_amount; grid_index++) { VolumeGrid *volume_grid = BKE_volume_grid_get(volume, grid_index); |