From 537fdbbfa2f6081bf8266b06a8a0ee78caa50ce8 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 23 Jun 2023 20:12:17 +0200 Subject: [PATCH] Fix: Revert changes in Mesh to Volume node and modifier to Blender 3.6 This brings back the `Fill Volume` and `Exterior Bandwidth` inputs in the Mesh to Volume node and modifier. Those existed in Blender 3.5 but were removed in 700d168a5c7f44daa623 because the way they were implemented did not use the openvdb api in the right way. While it's rare that people turned off the `Fill Volume` option, the exterior bandwidth was used more and can have significant impact on the result. Furthermore, there is no clear replacement for the functionality. Therefore, we decided to roll back the changes in 3.6 to avoid breaking compatibility. We intend to keep the changes in 4.0 for now, but need to work on a more clear short term replacement for the removed functionality. Pull Request: https://projects.blender.org/blender/blender/pulls/109297 --- source/blender/geometry/GEO_mesh_to_volume.hh | 2 + .../blender/geometry/intern/mesh_to_volume.cc | 70 +++++++++++++------ source/blender/makesdna/DNA_modifier_types.h | 7 ++ source/blender/makesrna/intern/rna_modifier.c | 11 +++ .../modifiers/intern/MOD_mesh_to_volume.cc | 24 +++++-- .../geometry/nodes/node_geo_mesh_to_volume.cc | 20 +++++- 6 files changed, 104 insertions(+), 30 deletions(-) diff --git a/source/blender/geometry/GEO_mesh_to_volume.hh b/source/blender/geometry/GEO_mesh_to_volume.hh index 9ef635a8e21..9a5ba012abc 100644 --- a/source/blender/geometry/GEO_mesh_to_volume.hh +++ b/source/blender/geometry/GEO_mesh_to_volume.hh @@ -49,6 +49,8 @@ VolumeGrid *fog_volume_grid_add_from_mesh(Volume *volume, const Mesh *mesh, const float4x4 &mesh_to_volume_space_transform, float voxel_size, + bool fill_volume, + float exterior_band_width, float interior_band_width, float density); /** diff --git a/source/blender/geometry/intern/mesh_to_volume.cc b/source/blender/geometry/intern/mesh_to_volume.cc index 8f35e4f03d3..f808c40cb38 100644 --- a/source/blender/geometry/intern/mesh_to_volume.cc +++ b/source/blender/geometry/intern/mesh_to_volume.cc @@ -97,19 +97,18 @@ float volume_compute_voxel_size(const Depsgraph *depsgraph, const float diagonal = math::distance(math::transform_point(transform, bb_max), math::transform_point(transform, bb_min)); - /* To get the approximate size per voxel, first subtract the exterior band from the requested - * voxel amount, then divide the diagonal with this value if it's bigger than 1. */ - const float voxel_size = - (diagonal / std::max(1.0f, float(res.settings.voxel_amount) - 2.0f * exterior_band_width)); - - /* Return the simplified voxel size. */ - return voxel_size / volume_simplify; + const float approximate_volume_side_length = diagonal + exterior_band_width * 2.0f; + const float voxel_size = approximate_volume_side_length / res.settings.voxel_amount / + volume_simplify; + return voxel_size; } static openvdb::FloatGrid::Ptr mesh_to_fog_volume_grid( const Mesh *mesh, const float4x4 &mesh_to_volume_space_transform, const float voxel_size, + const bool fill_volume, + const float exterior_band_width, const float interior_band_width, const float density) { @@ -123,21 +122,27 @@ static openvdb::FloatGrid::Ptr mesh_to_fog_volume_grid( mesh_to_index_space_transform.location() -= 0.5f; OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform}; - const float interior = std::max(1.0f, interior_band_width / voxel_size); - openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform( - voxel_size); - openvdb::FloatGrid::Ptr new_grid = openvdb::tools::meshToVolume( - mesh_adapter, *transform, 1.0f, interior); + /* Convert the bandwidths from object in index space. */ + const float exterior = MAX2(0.001f, exterior_band_width / voxel_size); + const float interior = MAX2(0.001f, interior_band_width / voxel_size); - openvdb::tools::sdfToFogVolume(*new_grid); - - if (density != 1.0f) { - openvdb::tools::foreach (new_grid->beginValueOn(), - [&](const openvdb::FloatGrid::ValueOnIter &iter) { - iter.modifyValue([&](float &value) { value *= density; }); - }); + openvdb::FloatGrid::Ptr new_grid; + if (fill_volume) { + /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */ + new_grid = openvdb::tools::meshToVolume( + mesh_adapter, {}, exterior, FLT_MAX); } + else { + new_grid = openvdb::tools::meshToVolume( + mesh_adapter, {}, exterior, interior); + } + + /* Give each grid cell a fixed density for now. */ + openvdb::tools::foreach ( + new_grid->beginValueOn(), + [density](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(density); }); + return new_grid; } @@ -185,12 +190,33 @@ VolumeGrid *fog_volume_grid_add_from_mesh(Volume *volume, const Mesh *mesh, const float4x4 &mesh_to_volume_space_transform, const float voxel_size, + const bool fill_volume, + const float exterior_band_width, const float interior_band_width, const float density) { - openvdb::FloatGrid::Ptr mesh_grid = mesh_to_fog_volume_grid( - mesh, mesh_to_volume_space_transform, voxel_size, interior_band_width, density); - return mesh_grid ? BKE_volume_grid_add_vdb(*volume, name, std::move(mesh_grid)) : nullptr; + VolumeGrid *c_grid = BKE_volume_grid_add(volume, name.c_str(), VOLUME_GRID_FLOAT); + openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast( + BKE_volume_grid_openvdb_for_write(volume, c_grid, false)); + + /* Generate grid from mesh */ + openvdb::FloatGrid::Ptr mesh_grid = mesh_to_fog_volume_grid(mesh, + mesh_to_volume_space_transform, + voxel_size, + fill_volume, + exterior_band_width, + interior_band_width, + density); + + if (mesh_grid != nullptr) { + /* Merge the generated grid. Should be cheap because grid has just been created. */ + grid->merge(*mesh_grid); + /* Change transform so that the index space is correctly transformed to object space. */ + grid->transform().postScale(voxel_size); + } + /* Set class to "Fog Volume". */ + grid->setGridClass(openvdb::GRID_FOG_VOLUME); + return c_grid; } VolumeGrid *sdf_volume_grid_add_from_mesh(Volume *volume, diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 90042e83581..8fb1f8e7d6f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2361,7 +2361,14 @@ typedef struct MeshToVolumeModifierData { * different. */ int voxel_amount; + /** If true, every cell in the enclosed volume gets a density. Otherwise, the interior_band_width + * is used. */ + char fill_volume; + char _pad1[3]; + + /** Band widths are in object space. */ float interior_band_width; + float exterior_band_width; float density; char _pad2[4]; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 1ac78b69d87..c54f1ecd805 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -7106,6 +7106,17 @@ static void rna_def_modifier_mesh_to_volume(BlenderRNA *brna) RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_fill_volume", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "fill_volume", 1); + RNA_def_property_ui_text( + prop, "Fill Volume", "Initialize the density grid in every cell inside the enclosed volume"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "exterior_band_width", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Exterior Band Width", "Width of the volume outside of the mesh"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "interior_band_width", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text( prop, "Interior Band Width", "Width of the gradient inside of the mesh"); diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index 0c0a9dddee4..c7dacd5ffb5 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -53,7 +53,9 @@ static void initData(ModifierData *md) mvmd->resolution_mode = MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT; mvmd->voxel_size = 0.1f; mvmd->voxel_amount = 32; - mvmd->interior_band_width = 0.2f; + mvmd->fill_volume = true; + mvmd->interior_band_width = 0.1f; + mvmd->exterior_band_width = 0.1f; mvmd->density = 1.0f; } @@ -89,7 +91,12 @@ static void panel_draw(const bContext * /*C*/, Panel *panel) { uiLayout *col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "interior_band_width", 0, nullptr, ICON_NONE); + uiItemR(col, ptr, "use_fill_volume", 0, nullptr, ICON_NONE); + uiItemR(col, ptr, "exterior_band_width", 0, nullptr, ICON_NONE); + + uiLayout *subcol = uiLayoutColumn(col, false); + uiLayoutSetActive(subcol, !mvmd->fill_volume); + uiItemR(subcol, ptr, "interior_band_width", 0, nullptr, ICON_NONE); } { uiLayout *col = uiLayoutColumn(layout, false); @@ -135,13 +142,13 @@ static Volume *mesh_to_volume(ModifierData *md, resolution.mode = (MeshToVolumeModifierResolutionMode)mvmd->resolution_mode; if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) { resolution.settings.voxel_amount = mvmd->voxel_amount; - if (resolution.settings.voxel_amount < 1.0f) { + if (resolution.settings.voxel_amount <= 0.0f) { return input_volume; } } else if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) { resolution.settings.voxel_size = mvmd->voxel_size; - if (resolution.settings.voxel_size < 1e-5f) { + if (resolution.settings.voxel_size <= 0.0f) { return input_volume; } } @@ -152,8 +159,11 @@ static Volume *mesh_to_volume(ModifierData *md, r_max = bb->vec[6]; }; - const float voxel_size = geometry::volume_compute_voxel_size( - ctx->depsgraph, bounds_fn, resolution, 0.0f, mesh_to_own_object_space_transform); + const float voxel_size = geometry::volume_compute_voxel_size(ctx->depsgraph, + bounds_fn, + resolution, + mvmd->exterior_band_width, + mesh_to_own_object_space_transform); /* Create a new volume. */ Volume *volume; @@ -170,6 +180,8 @@ static Volume *mesh_to_volume(ModifierData *md, mesh, mesh_to_own_object_space_transform, voxel_size, + mvmd->fill_volume, + mvmd->exterior_band_width, mvmd->interior_band_width, mvmd->density); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc index d47eb7eb78d..4919f886435 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc @@ -34,12 +34,21 @@ static void node_declare(NodeDeclarationBuilder &b) .max(FLT_MAX) .subtype(PROP_DISTANCE); b.add_input("Voxel Amount").default_value(64.0f).min(0.0f).max(FLT_MAX); + b.add_input(N_("Exterior Band Width")) + .default_value(0.1f) + .min(0.0f) + .max(FLT_MAX) + .subtype(PROP_DISTANCE) + .description(N_("Width of the volume outside of the mesh")); b.add_input("Interior Band Width") .default_value(0.2f) .min(0.0001f) .max(FLT_MAX) .subtype(PROP_DISTANCE) .description("Width of the gradient inside of the mesh"); + b.add_input(N_("Fill Volume")) + .default_value(true) + .description(N_("Initialize the density grid in every cell inside the enclosed volume")); b.add_output("Volume").translation_context(BLT_I18NCONTEXT_ID_ID); } @@ -79,7 +88,9 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams ¶ *(const NodeGeometryMeshToVolume *)params.node().storage; const float density = params.get_input("Density"); + const float exterior_band_width = params.get_input("Exterior Band Width"); const float interior_band_width = params.get_input("Interior Band Width"); + const bool fill_volume = params.get_input("Fill Volume"); geometry::MeshToVolumeResolution resolution; resolution.mode = (MeshToVolumeModifierResolutionMode)storage.resolution_mode; @@ -110,8 +121,11 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams ¶ r_max = max; }; - const float voxel_size = geometry::volume_compute_voxel_size( - params.depsgraph(), bounds_fn, resolution, 0.0f, mesh_to_volume_space_transform); + const float voxel_size = geometry::volume_compute_voxel_size(params.depsgraph(), + bounds_fn, + resolution, + exterior_band_width, + mesh_to_volume_space_transform); Volume *volume = reinterpret_cast(BKE_id_new_nomain(ID_VO, nullptr)); @@ -121,6 +135,8 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams ¶ &mesh, mesh_to_volume_space_transform, voxel_size, + fill_volume, + exterior_band_width, interior_band_width, density);