diff options
Diffstat (limited to 'source/blender/blenkernel/intern/volume.cc')
-rw-r--r-- | source/blender/blenkernel/intern/volume.cc | 168 |
1 files changed, 153 insertions, 15 deletions
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 |