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')
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh5
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc10
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/geometry/CMakeLists.txt16
-rw-r--r--source/blender/geometry/GEO_mesh_to_volume.hh50
-rw-r--r--source/blender/geometry/intern/mesh_to_volume.cc168
-rw-r--r--source/blender/makesdna/DNA_node_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c26
-rw-r--r--source/blender/modifiers/intern/MOD_mesh_to_volume.cc155
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc183
14 files changed, 501 insertions, 122 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 8d658c9be15..1d4291473bb 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -412,6 +412,11 @@ struct GeometrySet {
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
+ * Create a new geometry set that only contains the given volume.
+ */
+ static GeometrySet create_with_volume(
+ Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
* Create a new geometry set that only contains the given point cloud.
*/
static GeometrySet create_with_pointcloud(
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 4a84f8fc3c4..bad3e0005b8 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1498,6 +1498,7 @@ struct TexResult;
#define GEO_NODE_VOLUME_CUBE 1161
#define GEO_NODE_POINTS 1162
#define GEO_NODE_FIELD_ON_DOMAIN 1163
+#define GEO_NODE_MESH_TO_VOLUME 1164
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 1a43c4d01b0..70a39acf620 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -322,6 +322,16 @@ GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType owne
return geometry_set;
}
+GeometrySet GeometrySet::create_with_volume(Volume *volume, GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ if (volume != nullptr) {
+ VolumeComponent &component = geometry_set.get_component_for_write<VolumeComponent>();
+ component.replace(volume, ownership);
+ }
+ return geometry_set;
+}
+
GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership)
{
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index b6ab1e0174b..244c9ccd048 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4804,6 +4804,7 @@ static void registerGeometryNodes()
register_node_type_geo_mesh_subdivide();
register_node_type_geo_mesh_to_curve();
register_node_type_geo_mesh_to_points();
+ register_node_type_geo_mesh_to_volume();
register_node_type_geo_object_info();
register_node_type_geo_points();
register_node_type_geo_points_to_vertices();
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 531487a45e2..f0fb5c5c9af 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -19,6 +19,7 @@ set(SRC
intern/mesh_merge_by_distance.cc
intern/mesh_primitive_cuboid.cc
intern/mesh_to_curve_convert.cc
+ intern/mesh_to_volume.cc
intern/point_merge_by_distance.cc
intern/realize_instances.cc
intern/resample_curves.cc
@@ -29,6 +30,7 @@ set(SRC
GEO_mesh_merge_by_distance.hh
GEO_mesh_primitive_cuboid.hh
GEO_mesh_to_curve.hh
+ GEO_mesh_to_volume.hh
GEO_point_merge_by_distance.hh
GEO_realize_instances.hh
GEO_resample_curves.hh
@@ -41,6 +43,20 @@ set(LIB
bf_blenlib
)
+if(WITH_OPENVDB)
+ list(APPEND INC
+ ../../../intern/openvdb
+ )
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ bf_intern_openvdb
+ ${OPENVDB_LIBRARIES}
+ )
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+endif()
+
if(WITH_TBB)
add_definitions(-DWITH_TBB)
diff --git a/source/blender/geometry/GEO_mesh_to_volume.hh b/source/blender/geometry/GEO_mesh_to_volume.hh
new file mode 100644
index 00000000000..384293df336
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_to_volume.hh
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_float4x4.hh"
+#include "BLI_string_ref.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#pragma once
+
+struct Volume;
+struct VolumeGrid;
+struct Depsgraph;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+struct MeshToVolumeResolution {
+ MeshToVolumeModifierResolutionMode mode;
+ union {
+ float voxel_size;
+ float voxel_amount;
+ } settings;
+};
+
+#ifdef WITH_OPENVDB
+float volume_compute_voxel_size(const Depsgraph *depsgraph,
+ const float3 &bb_min,
+ const float3 &bb_max,
+ const MeshToVolumeResolution resolution,
+ float exterior_band_width,
+ const float4x4 &transform);
+/**
+ * Add a new VolumeGrid to the Volume by converting the supplied mesh
+ */
+VolumeGrid *volume_grid_add_from_mesh(Volume *volume,
+ const StringRefNull name,
+ 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);
+#endif
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_to_volume.cc b/source/blender/geometry/intern/mesh_to_volume.cc
new file mode 100644
index 00000000000..93a424f9a94
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_to_volume.cc
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh_runtime.h"
+#include "BKE_volume.h"
+
+#include "GEO_mesh_to_volume.hh"
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/VolumeToMesh.h>
+
+namespace blender::geometry {
+
+/* This class follows the MeshDataAdapter interface from openvdb. */
+class OpenVDBMeshAdapter {
+ private:
+ Span<MVert> vertices_;
+ Span<MLoop> loops_;
+ Span<MLoopTri> looptris_;
+ float4x4 transform_;
+
+ public:
+ OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform);
+ size_t polygonCount() const;
+ size_t pointCount() const;
+ size_t vertexCount(size_t UNUSED(polygon_index)) const;
+ void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const;
+};
+
+OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform)
+ : vertices_(mesh.mvert, mesh.totvert), loops_(mesh.mloop, mesh.totloop), transform_(transform)
+{
+ /* This only updates a cache and can be considered to be logically const. */
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(&mesh);
+ const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
+ looptris_ = Span(looptris, looptris_len);
+}
+
+size_t OpenVDBMeshAdapter::polygonCount() const
+{
+ return static_cast<size_t>(looptris_.size());
+}
+
+size_t OpenVDBMeshAdapter::pointCount() const
+{
+ return static_cast<size_t>(vertices_.size());
+}
+
+size_t OpenVDBMeshAdapter::vertexCount(size_t UNUSED(polygon_index)) const
+{
+ /* All polygons are triangles. */
+ return 3;
+}
+
+void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
+ size_t vertex_index,
+ openvdb::Vec3d &pos) const
+{
+ const MLoopTri &looptri = looptris_[polygon_index];
+ const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
+ const float3 transformed_co = transform_ * float3(vertex.co);
+ pos = &transformed_co.x;
+}
+
+float volume_compute_voxel_size(const Depsgraph *depsgraph,
+ const float3 &bb_min,
+ const float3 &bb_max,
+ const MeshToVolumeResolution res,
+ const float exterior_band_width,
+ const float4x4 &transform)
+{
+ const float volume_simplify = BKE_volume_simplify_factor(depsgraph);
+ if (volume_simplify == 0.0f) {
+ return 0.0f;
+ }
+
+ if (res.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ return res.settings.voxel_size / volume_simplify;
+ }
+ if (res.settings.voxel_amount <= 0) {
+ return 0;
+ }
+ /* Compute the voxel size based on the desired number of voxels and the approximated bounding
+ * box of the volume. */
+ const float diagonal = math::distance(transform * bb_max, transform * bb_min);
+ 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_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)
+{
+ if (voxel_size == 0.0f) {
+ return nullptr;
+ }
+
+ float4x4 mesh_to_index_space_transform;
+ scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
+ mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_volume_space_transform.values);
+ /* Better align generated grid with the source mesh. */
+ add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
+
+ OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
+
+ /* 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::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<openvdb::FloatGrid>(
+ mesh_adapter, {}, exterior, FLT_MAX);
+ }
+ else {
+ new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
+ 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;
+}
+
+VolumeGrid *volume_grid_add_from_mesh(Volume *volume,
+ const StringRefNull name,
+ 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)
+{
+ VolumeGrid *c_grid = BKE_volume_grid_add(volume, name.c_str(), VOLUME_GRID_FLOAT);
+ openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
+ BKE_volume_grid_openvdb_for_write(volume, c_grid, false));
+
+ /* Generate grid from mesh */
+ openvdb::FloatGrid::Ptr mesh_grid = mesh_to_volume_grid(mesh,
+ mesh_to_volume_space_transform,
+ voxel_size,
+ fill_volume,
+ exterior_band_width,
+ interior_band_width,
+ density);
+
+ /* Merge the generated grid. Should be cheap because grid has just been created. */
+ grid->merge(*mesh_grid);
+ /* Set class to "Fog Volume". */
+ grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+ /* Change transform so that the index space is correctly transformed to object space. */
+ grid->transform().postScale(voxel_size);
+ return c_grid;
+}
+} // namespace blender::geometry
+#endif
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 25c8a1f1514..3f3eb6e0571 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1248,6 +1248,11 @@ typedef struct NodeGeometryVolumeToMesh {
uint8_t resolution_mode;
} NodeGeometryVolumeToMesh;
+typedef struct NodeGeometryMeshToVolume {
+ /* MeshToVolumeModifierResolutionMode */
+ uint8_t resolution_mode;
+} NodeGeometryMeshToVolume;
+
typedef struct NodeGeometrySubdivisionSurface {
/* eSubsurfUVSmooth. */
uint8_t uv_smooth;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 1a8f47605a3..0ad109e711f 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -9970,6 +9970,32 @@ static void def_geo_volume_to_mesh(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_mesh_to_volume(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem resolution_mode_items[] = {
+ {MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT,
+ "VOXEL_AMOUNT",
+ 0,
+ "Amount",
+ "Desired number of voxels along one axis"},
+ {MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE,
+ "VOXEL_SIZE",
+ 0,
+ "Size",
+ "Desired voxel side length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryMeshToVolume", "storage");
+
+ prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, resolution_mode_items);
+ RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_mesh_circle(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
index 11af907adc8..a0ebc9cfdcb 100644
--- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
+++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
@@ -22,6 +22,8 @@
#include "DEG_depsgraph.h"
+#include "GEO_mesh_to_volume.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -39,59 +41,6 @@
#include "RNA_access.h"
#include "RNA_prototypes.h"
-#ifdef WITH_OPENVDB
-# include <openvdb/openvdb.h>
-# include <openvdb/tools/MeshToVolume.h>
-#endif
-
-#ifdef WITH_OPENVDB
-namespace blender {
-/* This class follows the MeshDataAdapter interface from openvdb. */
-class OpenVDBMeshAdapter {
- private:
- Span<MVert> vertices_;
- Span<MLoop> loops_;
- Span<MLoopTri> looptris_;
- float4x4 transform_;
-
- public:
- OpenVDBMeshAdapter(Mesh &mesh, float4x4 transform)
- : vertices_(mesh.mvert, mesh.totvert),
- loops_(mesh.mloop, mesh.totloop),
- transform_(transform)
- {
- const MLoopTri *looptries = BKE_mesh_runtime_looptri_ensure(&mesh);
- const int looptries_len = BKE_mesh_runtime_looptri_len(&mesh);
- looptris_ = Span(looptries, looptries_len);
- }
-
- size_t polygonCount() const
- {
- return static_cast<size_t>(looptris_.size());
- }
-
- size_t pointCount() const
- {
- return static_cast<size_t>(vertices_.size());
- }
-
- size_t vertexCount(size_t UNUSED(polygon_index)) const
- {
- /* All polygons are triangles. */
- return 3;
- }
-
- void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const
- {
- const MLoopTri &looptri = looptris_[polygon_index];
- const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
- const float3 transformed_co = transform_ * float3(vertex.co);
- pos = &transformed_co.x;
- }
-};
-} // namespace blender
-#endif
-
static void initData(ModifierData *md)
{
MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
@@ -163,35 +112,6 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_MeshToVolume, panel_draw);
}
-#ifdef WITH_OPENVDB
-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 / volume_simplify;
- }
- if (mvmd->voxel_amount <= 0) {
- return 0;
- }
- /* Compute the voxel size based on the desired number of voxels and the approximated bounding box
- * of the volume. */
- const BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
- const float diagonal = math::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 / volume_simplify;
- return voxel_size;
-}
-#endif
-
static Volume *mesh_to_volume(ModifierData *md,
const ModifierEvalContext *ctx,
Volume *input_volume)
@@ -213,51 +133,42 @@ static Volume *mesh_to_volume(ModifierData *md,
const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) *
float4x4(object_to_convert->obmat);
- const float voxel_size = compute_voxel_size(ctx, mvmd, mesh_to_own_object_space_transform);
- if (voxel_size == 0.0f) {
- return input_volume;
- }
-
- float4x4 mesh_to_index_space_transform;
- scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
- mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_own_object_space_transform.values);
- /* Better align generated grid with the source mesh. */
- add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
-
- OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
-
- /* Convert the bandwidths from object in index space. */
- const float exterior_band_width = MAX2(0.001f, mvmd->exterior_band_width / voxel_size);
- const float interior_band_width = MAX2(0.001f, mvmd->interior_band_width / voxel_size);
-
- openvdb::FloatGrid::Ptr new_grid;
- if (mvmd->fill_volume) {
- /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
- new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
- mesh_adapter, {}, exterior_band_width, FLT_MAX);
+ const BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
+ geometry::MeshToVolumeResolution resolution;
+ 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 <= 0.0f) {
+ return input_volume;
+ }
}
- else {
- new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
- mesh_adapter, {}, exterior_band_width, interior_band_width);
+ else if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = mvmd->voxel_size;
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return input_volume;
+ }
}
- /* 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 = openvdb::gridPtrCast<openvdb::FloatGrid>(
- BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false));
+ const float voxel_size = geometry::volume_compute_voxel_size(ctx->depsgraph,
+ bb->vec[0],
+ bb->vec[6],
+ resolution,
+ mvmd->exterior_band_width,
+ mesh_to_own_object_space_transform);
- /* Merge the generated grid into the density grid. Should be cheap because density_grid has just
- * been created as well. */
- density_grid->merge(*new_grid);
-
- /* Change transform so that the index space is correctly transformed to object space. */
- density_grid->transform().postScale(voxel_size);
+ /* Create a new volume. */
+ Volume *volume = BKE_volume_new_for_eval(input_volume);
- /* Give each grid cell a fixed density for now. */
- openvdb::tools::foreach (
- density_grid->beginValueOn(),
- [&](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(mvmd->density); });
+ /* Convert mesh to grid and add to volume. */
+ geometry::volume_grid_add_from_mesh(volume,
+ "density",
+ mesh,
+ mesh_to_own_object_space_transform,
+ voxel_size,
+ mvmd->fill_volume,
+ mvmd->exterior_band_width,
+ mvmd->interior_band_width,
+ mvmd->density);
return volume;
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 56d1472e840..889ab2a81e4 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -102,6 +102,7 @@ void register_node_type_geo_mesh_primitive_uv_sphere(void);
void register_node_type_geo_mesh_subdivide(void);
void register_node_type_geo_mesh_to_curve(void);
void register_node_type_geo_mesh_to_points(void);
+void register_node_type_geo_mesh_to_volume(void);
void register_node_type_geo_object_info(void);
void register_node_type_geo_points(void);
void register_node_type_geo_points_to_vertices(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 62a6f85a04c..f9925924260 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -357,6 +357,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRI
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "")
DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "")
+DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh To Volume", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
DefNode(GeometryNode, GEO_NODE_POINTS, 0, "POINTS", Points, "Points", "")
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "")
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 1fad6ce5b34..9ef3151ddab 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -112,6 +112,7 @@ set(SRC
nodes/node_geo_mesh_subdivide.cc
nodes/node_geo_mesh_to_curve.cc
nodes/node_geo_mesh_to_points.cc
+ nodes/node_geo_mesh_to_volume.cc
nodes/node_geo_object_info.cc
nodes/node_geo_points.cc
nodes/node_geo_points_to_vertices.cc
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
new file mode 100644
index 00000000000..9d8a77c3947
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DEG_depsgraph_query.h"
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_object.h"
+#include "BKE_volume.h"
+
+#include "GEO_mesh_to_volume.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_mesh_to_volume_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshToVolume)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.01f).max(FLT_MAX);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .max(FLT_MAX)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f).max(FLT_MAX);
+ b.add_input<decl::Float>(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<decl::Float>(N_("Interior Band Width"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(FLT_MAX)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Width of the volume inside of the mesh"));
+ b.add_input<decl::Bool>(N_("Fill Volume"))
+ .default_value(true)
+ .description(N_("Initialize the density grid in every cell inside the enclosed volume"));
+ b.add_output<decl::Geometry>(N_("Volume"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)MEM_callocN(
+ sizeof(NodeGeometryMeshToVolume), __func__);
+ data->resolution_mode = MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)node->storage;
+
+ bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
+ bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
+ nodeSetSocketAvailability(ntree,
+ voxel_amount_socket,
+ data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(ntree,
+ voxel_size_socket,
+ data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE);
+}
+
+#ifdef WITH_OPENVDB
+
+static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams &params)
+{
+ const NodeGeometryMeshToVolume &storage =
+ *(const NodeGeometryMeshToVolume *)params.node().storage;
+
+ const float density = params.get_input<float>("Density");
+ const float exterior_band_width = params.get_input<float>("Exterior Band Width");
+ const float interior_band_width = params.get_input<float>("Interior Band Width");
+ const bool fill_volume = params.get_input<bool>("Fill Volume");
+
+ geometry::MeshToVolumeResolution resolution;
+ resolution.mode = (MeshToVolumeModifierResolutionMode)storage.resolution_mode;
+ if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) {
+ resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
+ if (resolution.settings.voxel_amount <= 0.0f) {
+ return nullptr;
+ }
+ }
+ else if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return nullptr;
+ }
+ }
+
+ float3 min, max;
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_wrapper_minmax(&mesh, min, max)) {
+ min = float3(-1.0f);
+ max = float3(1.0f);
+ }
+
+ const float4x4 mesh_to_volume_space_transform = float4x4::identity();
+
+ const float voxel_size = geometry::volume_compute_voxel_size(params.depsgraph(),
+ min,
+ max,
+ resolution,
+ exterior_band_width,
+ mesh_to_volume_space_transform);
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ /* Convert mesh to grid and add to volume. */
+ geometry::volume_grid_add_from_mesh(volume,
+ "density",
+ &mesh,
+ mesh_to_volume_space_transform,
+ voxel_size,
+ fill_volume,
+ exterior_band_width,
+ interior_band_width,
+ density);
+
+ return volume;
+}
+
+#endif /* WITH_OPENVDB */
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+#ifdef WITH_OPENVDB
+ GeometrySet geometry_set(params.extract_input<GeometrySet>("Mesh"));
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ Volume *volume = create_volume_from_mesh(*geometry_set.get_mesh_for_read(), params);
+ geometry_set.replace_volume(volume);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES});
+ }
+ });
+ params.set_output("Volume", std::move(geometry_set));
+#else
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+ params.set_default_remaining_outputs();
+ return;
+#endif
+}
+
+} // namespace blender::nodes::node_geo_mesh_to_volume_cc
+
+void register_node_type_geo_mesh_to_volume()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_volume_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_VOLUME, "Mesh to Volume", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_size(&ntype, 200, 120, 700);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ node_type_storage(
+ &ntype, "NodeGeometryMeshToVolume", node_free_standard_storage, node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}