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:
authorErik Abrahamsson <ecke101@gmail.com>2022-06-29 18:56:17 +0300
committerHans Goudey <h.goudey@me.com>2022-06-29 18:56:17 +0300
commit1516f7dcde34a4a31f6f3d04eac5f60310ea32b7 (patch)
treeee5a6c53cad8944e6768d1548a1a15ee2db62e08 /source/blender
parent6b508eb012b929b34e893f71a785580562cc9a6a (diff)
Geometry Nodes: Add Mesh To Volume Node
This adds a Mesh To Volume Node T86838 based on the existing modifier. The mesh to volume conversion is implemented in the geometry module, and shared between the node and the modifier. Currently the node outputs a grid with the name "density". This may change in the future depending on the decisions made in T91668. The original patch was by Kris (@Metricity), further implementation by Geramy Loveless (@GeramyLoveless), then finished by Erik Abrahamsson (@erik85). Differential Revision: https://developer.blender.org/D10895
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);
+}