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);