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_node.h3
-rw-r--r--source/blender/blenkernel/BKE_volume.h5
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh32
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/blenkernel/intern/volume.cc17
-rw-r--r--source/blender/blenkernel/intern/volume_to_mesh.cc93
-rw-r--r--source/blender/blenloader/intern/versioning_290.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.c3
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-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/nodes/legacy/node_geo_volume_to_mesh.cc173
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc127
13 files changed, 383 insertions, 77 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index c868eb414f7..8daa96164ef 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1442,7 +1442,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_COLLECTION_INFO 1023
#define GEO_NODE_IS_VIEWPORT 1024
#define GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY 1025
-#define GEO_NODE_VOLUME_TO_MESH 1026
+#define GEO_NODE_LEGACY_VOLUME_TO_MESH 1026
#define GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ 1027
#define GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ 1028
#define GEO_NODE_SUBDIVIDE_MESH 1029
@@ -1548,6 +1548,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_TO_POINTS 1130
#define GEO_NODE_INSTANCES_TO_POINTS 1131
#define GEO_NODE_IMAGE_TEXTURE 1132
+#define GEO_NODE_VOLUME_TO_MESH 1133
/** \} */
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 5fe0d54c2cf..601e0cf26a9 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -160,6 +160,7 @@ bool BKE_volume_save(const struct Volume *volume,
#ifdef __cplusplus
# include "BLI_float3.hh"
# include "BLI_float4x4.hh"
+# include "BLI_string_ref.hh"
bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::float3 &r_max);
@@ -167,6 +168,10 @@ bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::f
# include <openvdb/openvdb.h>
# include <openvdb/points/PointDataGrid.h>
+VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume,
+ blender::StringRef name,
+ openvdb::GridBase::Ptr vdb_grid);
+
bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid,
blender::float3 &r_min,
blender::float3 &r_max);
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index 1f6e89636c4..9532da8c23c 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_span.hh"
+
#include "DNA_modifier_types.h"
#ifdef WITH_OPENVDB
@@ -33,10 +35,40 @@ struct VolumeToMeshResolution {
};
#ifdef WITH_OPENVDB
+
+/**
+ * The result of converting a volume grid to mesh data, in the format used by the OpenVDB API.
+ */
+struct OpenVDBMeshData {
+ std::vector<openvdb::Vec3s> verts;
+ std::vector<openvdb::Vec3I> tris;
+ std::vector<openvdb::Vec4I> quads;
+ bool is_empty() const
+ {
+ return verts.empty();
+ }
+};
+
struct Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const VolumeToMeshResolution &resolution,
const float threshold,
const float adaptivity);
+
+struct OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
+ const VolumeToMeshResolution &resolution,
+ const float threshold,
+ const float adaptivity);
+
+void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
+ const Span<openvdb::Vec3I> vdb_tris,
+ const Span<openvdb::Vec4I> vdb_quads,
+ const int vert_offset,
+ const int poly_offset,
+ const int loop_offset,
+ MutableSpan<MVert> verts,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops);
+
#endif
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index fb2110d7e53..8494c51a66e 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -5753,6 +5753,7 @@ static void registerGeometryNodes()
register_node_type_geo_legacy_select_by_handle_type();
register_node_type_geo_legacy_select_by_material();
register_node_type_geo_legacy_subdivision_surface();
+ register_node_type_geo_legacy_volume_to_mesh();
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_capture();
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 7e7a40d8e9b..a72b5268e1d 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
@@ -71,6 +72,7 @@ static CLG_LogRef LOG = {"bke.volume"};
using blender::float3;
using blender::float4x4;
using blender::IndexRange;
+using blender::StringRef;
#ifdef WITH_OPENVDB
# include <atomic>
@@ -1451,6 +1453,21 @@ VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType
#endif
}
+#ifdef WITH_OPENVDB
+VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume,
+ const StringRef name,
+ openvdb::GridBase::Ptr vdb_grid)
+{
+ VolumeGridVector &grids = *volume.runtime.grids;
+ BLI_assert(BKE_volume_grid_find_for_read(&volume, name.data()) == nullptr);
+ BLI_assert(BKE_volume_grid_type_openvdb(*vdb_grid) != VOLUME_GRID_UNKNOWN);
+
+ vdb_grid->setName(name);
+ grids.emplace_back(vdb_grid);
+ return &grids.back();
+}
+#endif
+
void BKE_volume_grid_remove(Volume *volume, VolumeGrid *grid)
{
#ifdef WITH_OPENVDB
diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc
index e9d6eea4614..6e465b2fdf0 100644
--- a/source/blender/blenkernel/intern/volume_to_mesh.cc
+++ b/source/blender/blenkernel/intern/volume_to_mesh.cc
@@ -121,46 +121,66 @@ struct VolumeToMeshOp {
}
};
-static Mesh *new_mesh_from_openvdb_data(Span<openvdb::Vec3s> verts,
- Span<openvdb::Vec3I> tris,
- Span<openvdb::Vec4I> quads)
+/**
+ * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure.
+ * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple
+ * meshes later on.
+ */
+void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
+ const Span<openvdb::Vec3I> vdb_tris,
+ const Span<openvdb::Vec4I> vdb_quads,
+ const int vert_offset,
+ const int poly_offset,
+ const int loop_offset,
+ MutableSpan<MVert> verts,
+ MutableSpan<MPoly> polys,
+ MutableSpan<MLoop> loops)
{
- const int tot_loops = 3 * tris.size() + 4 * quads.size();
- const int tot_polys = tris.size() + quads.size();
-
- Mesh *mesh = BKE_mesh_new_nomain(verts.size(), 0, 0, tot_loops, tot_polys);
-
/* Write vertices. */
- for (const int i : verts.index_range()) {
- const blender::float3 co = blender::float3(verts[i].asV());
- copy_v3_v3(mesh->mvert[i].co, co);
+ for (const int i : vdb_verts.index_range()) {
+ const blender::float3 co = blender::float3(vdb_verts[i].asV());
+ copy_v3_v3(verts[vert_offset + i].co, co);
}
/* Write triangles. */
- for (const int i : tris.index_range()) {
- mesh->mpoly[i].loopstart = 3 * i;
- mesh->mpoly[i].totloop = 3;
+ for (const int i : vdb_tris.index_range()) {
+ polys[poly_offset + i].loopstart = loop_offset + 3 * i;
+ polys[poly_offset + i].totloop = 3;
for (int j = 0; j < 3; j++) {
/* Reverse vertex order to get correct normals. */
- mesh->mloop[3 * i + j].v = tris[i][2 - j];
+ loops[loop_offset + 3 * i + j].v = vert_offset + vdb_tris[i][2 - j];
}
}
/* Write quads. */
- const int poly_offset = tris.size();
- const int loop_offset = tris.size() * 3;
- for (const int i : quads.index_range()) {
- mesh->mpoly[poly_offset + i].loopstart = loop_offset + 4 * i;
- mesh->mpoly[poly_offset + i].totloop = 4;
+ const int quad_offset = poly_offset + vdb_tris.size();
+ const int quad_loop_offset = loop_offset + vdb_tris.size() * 3;
+ for (const int i : vdb_quads.index_range()) {
+ polys[quad_offset + i].loopstart = quad_loop_offset + 4 * i;
+ polys[quad_offset + i].totloop = 4;
for (int j = 0; j < 4; j++) {
/* Reverse vertex order to get correct normals. */
- mesh->mloop[loop_offset + 4 * i + j].v = quads[i][3 - j];
+ loops[quad_loop_offset + 4 * i + j].v = vert_offset + vdb_quads[i][3 - j];
}
}
+}
- BKE_mesh_calc_edges(mesh, false, false);
- BKE_mesh_normals_tag_dirty(mesh);
- return mesh;
+/**
+ * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and
+ * triangle indices.
+ */
+bke::OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
+ const VolumeToMeshResolution &resolution,
+ const float threshold,
+ const float adaptivity)
+{
+ const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+
+ VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity};
+ if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) {
+ return {};
+ }
+ return {std::move(to_mesh_op.verts), std::move(to_mesh_op.tris), std::move(to_mesh_op.quads)};
}
Mesh *volume_to_mesh(const openvdb::GridBase &grid,
@@ -168,14 +188,27 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const float threshold,
const float adaptivity)
{
- const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
+ const bke::OpenVDBMeshData mesh_data = volume_to_mesh_data(
+ grid, resolution, threshold, adaptivity);
+
+ const int tot_loops = 3 * mesh_data.tris.size() + 4 * mesh_data.quads.size();
+ const int tot_polys = mesh_data.tris.size() + mesh_data.quads.size();
+ Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, 0, tot_loops, tot_polys);
+
+ fill_mesh_from_openvdb_data(mesh_data.verts,
+ mesh_data.tris,
+ mesh_data.quads,
+ 0,
+ 0,
+ 0,
+ {mesh->mvert, mesh->totvert},
+ {mesh->mpoly, mesh->totpoly},
+ {mesh->mloop, mesh->totloop});
- VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity};
- if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) {
- return nullptr;
- }
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_normals_tag_dirty(mesh);
- return new_mesh_from_openvdb_data(to_mesh_op.verts, to_mesh_op.tris, to_mesh_op.quads);
+ return mesh;
}
#endif /* WITH_OPENVDB */
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index d2c722f8be7..def14768ec6 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1985,7 +1985,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 293, 18)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_VOLUME_TO_MESH, "Grid", "Density");
+ version_node_socket_name(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Grid", "Density");
}
}
FOREACH_NODETREE_END;
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 57447db8723..d0d6c1471b7 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -967,7 +967,7 @@ static bool geometry_node_is_293_legacy(const short node_type)
/* Maybe legacy: Special case for grid names? Or finish patch from level set branch to
* generate a mesh for all grids in the volume. */
- case GEO_NODE_VOLUME_TO_MESH:
+ case GEO_NODE_LEGACY_VOLUME_TO_MESH:
return false;
/* Legacy: Transferred *all* attributes before, will not transfer all built-ins now. */
@@ -2098,6 +2098,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
version_node_id(ntree, FN_NODE_SLICE_STRING, "FunctionNodeSliceString");
version_geometry_nodes_set_position_node_offset(ntree);
+ version_node_id(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "GeometryNodeLegacyVolumeToMesh");
}
/* Keep this block, even when empty. */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 657d0d11441..acf0ab9b224 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -193,6 +193,8 @@ set(SRC
geometry/nodes/legacy/node_geo_raycast.cc
geometry/nodes/legacy/node_geo_select_by_material.cc
geometry/nodes/legacy/node_geo_subdivision_surface.cc
+ geometry/nodes/legacy/node_geo_volume_to_mesh.cc
+
geometry/nodes/node_geo_attribute_capture.cc
geometry/nodes/node_geo_attribute_remove.cc
geometry/nodes/node_geo_attribute_statistic.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 6702443e20e..d6f0b511861 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -47,6 +47,7 @@ void register_node_type_geo_legacy_curve_subdivide(void);
void register_node_type_geo_legacy_edge_split(void);
void register_node_type_geo_legacy_subdivision_surface(void);
void register_node_type_geo_legacy_raycast(void);
+void register_node_type_geo_legacy_volume_to_mesh(void);
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_capture(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 7fd4840489e..af9685fcf0d 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -321,6 +321,7 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_POINTS_TO_VOLUME, def_geo_legacy_points_to
DefNode(GeometryNode, GEO_NODE_LEGACY_RAYCAST, def_geo_legacy_raycast, "LEGACY_RAYCAST", LegacyRaycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_MATERIAL", LegacySelectByMaterial, "Select by Material", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
+DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "")
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc
new file mode 100644
index 00000000000..45f55dcf92e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc
@@ -0,0 +1,173 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DEG_depsgraph_query.h"
+#ifdef WITH_OPENVDB
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/VolumeToMesh.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_volume.h"
+#include "BKE_volume_to_mesh.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes {
+
+static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::String>("Density");
+ b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
+ b.add_input<decl::Float>("Threshold").default_value(0.1f).min(0.0f);
+ b.add_input<decl::Float>("Adaptivity").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Geometry>("Geometry");
+}
+
+static void geo_node_volume_to_mesh_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 geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
+ sizeof(NodeGeometryVolumeToMesh), __func__);
+ data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
+
+ bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
+ bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
+ STRNCPY(grid_socket_value->value, "density");
+
+ node->storage = data;
+}
+
+static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
+
+ bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
+ bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
+ nodeSetSocketAvailability(voxel_amount_socket,
+ data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(voxel_size_socket,
+ data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
+}
+
+#ifdef WITH_OPENVDB
+
+static void create_mesh_from_volume(GeometrySet &geometry_set_in,
+ GeometrySet &geometry_set_out,
+ GeoNodeExecParams &params)
+{
+ if (!geometry_set_in.has<VolumeComponent>()) {
+ return;
+ }
+
+ const NodeGeometryVolumeToMesh &storage =
+ *(const NodeGeometryVolumeToMesh *)params.node().storage;
+
+ bke::VolumeToMeshResolution resolution;
+ resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
+ resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
+ if (resolution.settings.voxel_amount <= 0.0f) {
+ return;
+ }
+ }
+ else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return;
+ }
+ }
+
+ const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
+ const Volume *volume = component->get_for_read();
+ if (volume == nullptr) {
+ return;
+ }
+
+ const Main *bmain = DEG_get_bmain(params.depsgraph());
+ BKE_volume_load(volume, bmain);
+
+ const std::string grid_name = params.get_input<std::string>("Density");
+ const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
+ if (volume_grid == nullptr) {
+ return;
+ }
+
+ float threshold = params.get_input<float>("Threshold");
+ float adaptivity = params.get_input<float>("Adaptivity");
+
+ const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
+ if (mesh == nullptr) {
+ return;
+ }
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
+ dst_component.replace(mesh);
+}
+
+#endif /* WITH_OPENVDB */
+
+static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
+ GeometrySet geometry_set_out;
+
+#ifdef WITH_OPENVDB
+ create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
+#else
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+#endif
+
+ params.set_output("Geometry", geometry_set_out);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_legacy_volume_to_mesh()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
+ ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare;
+ node_type_storage(
+ &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
+ node_type_size(&ntype, 170, 120, 700);
+ node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init);
+ node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update);
+ ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec;
+ ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index d1fb22f4ba2..c0084de367f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -39,13 +39,12 @@ namespace blender::nodes {
static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>("Geometry");
- b.add_input<decl::String>("Density");
+ b.add_input<decl::Geometry>("Volume");
b.add_input<decl::Float>("Voxel Size").default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>("Voxel Amount").default_value(64.0f).min(0.0f);
b.add_input<decl::Float>("Threshold").default_value(0.1f).min(0.0f);
b.add_input<decl::Float>("Adaptivity").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Geometry>("Geometry");
+ b.add_output<decl::Geometry>("Mesh");
}
static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -60,11 +59,6 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node)
NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
sizeof(NodeGeometryVolumeToMesh), __func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
-
- bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
- bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
- STRNCPY(grid_socket_value->value, "density");
-
node->storage = data;
}
@@ -82,75 +76,120 @@ static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node
#ifdef WITH_OPENVDB
-static void create_mesh_from_volume(GeometrySet &geometry_set_in,
- GeometrySet &geometry_set_out,
- GeoNodeExecParams &params)
+static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
{
- if (!geometry_set_in.has<VolumeComponent>()) {
- return;
- }
-
const NodeGeometryVolumeToMesh &storage =
*(const NodeGeometryVolumeToMesh *)params.node().storage;
bke::VolumeToMeshResolution resolution;
resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
- resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
- if (resolution.settings.voxel_amount <= 0.0f) {
- return;
- }
+ resolution.settings.voxel_amount = std::max(params.get_input<float>("Voxel Amount"), 0.0f);
}
else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
- resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
- if (resolution.settings.voxel_size <= 0.0f) {
- return;
- }
+ resolution.settings.voxel_size = std::max(params.get_input<float>("Voxel Size"), 0.0f);
+ }
+
+ return resolution;
+}
+
+static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> grids,
+ const float threshold,
+ const float adaptivity,
+ const bke::VolumeToMeshResolution &resolution)
+{
+ Array<bke::OpenVDBMeshData> mesh_data(grids.size());
+ for (const int i : grids.index_range()) {
+ mesh_data[i] = bke::volume_to_mesh_data(*grids[i], resolution, threshold, adaptivity);
+ }
+
+ int vert_offset = 0;
+ int poly_offset = 0;
+ int loop_offset = 0;
+ Array<int> vert_offsets(mesh_data.size());
+ Array<int> poly_offsets(mesh_data.size());
+ Array<int> loop_offsets(mesh_data.size());
+ for (const int i : grids.index_range()) {
+ const bke::OpenVDBMeshData &data = mesh_data[i];
+ vert_offsets[i] = vert_offset;
+ poly_offsets[i] = poly_offset;
+ loop_offsets[i] = loop_offset;
+ vert_offset += data.verts.size();
+ poly_offset += (data.tris.size() + data.quads.size());
+ loop_offset += (3 * data.tris.size() + 4 * data.quads.size());
}
- const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
- const Volume *volume = component->get_for_read();
+ Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, 0, loop_offset, poly_offset);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
+ MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+ MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
+
+ for (const int i : grids.index_range()) {
+ const bke::OpenVDBMeshData &data = mesh_data[i];
+ bke::fill_mesh_from_openvdb_data(data.verts,
+ data.tris,
+ data.quads,
+ vert_offsets[i],
+ poly_offsets[i],
+ loop_offsets[i],
+ verts,
+ polys,
+ loops);
+ }
+
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_normals_tag_dirty(mesh);
+
+ return mesh;
+}
+
+static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParams &params)
+{
+ const Volume *volume = geometry_set.get_volume_for_read();
if (volume == nullptr) {
- return;
+ return nullptr;
}
+ const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
const Main *bmain = DEG_get_bmain(params.depsgraph());
BKE_volume_load(volume, bmain);
- const std::string grid_name = params.get_input<std::string>("Density");
- const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
- if (volume_grid == nullptr) {
- return;
+ Vector<openvdb::GridBase::ConstPtr> grids;
+ for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
+ const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
+ openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
+ grids.append(std::move(grid));
}
- float threshold = params.get_input<float>("Threshold");
- float adaptivity = params.get_input<float>("Adaptivity");
-
- const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
- Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
- if (mesh == nullptr) {
- return;
+ if (grids.is_empty()) {
+ return nullptr;
}
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
- dst_component.replace(mesh);
+
+ return create_mesh_from_volume_grids(grids,
+ params.get_input<float>("Threshold"),
+ params.get_input<float>("Adaptivity"),
+ resolution);
}
#endif /* WITH_OPENVDB */
static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params)
{
- GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
- GeometrySet geometry_set_out;
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
#ifdef WITH_OPENVDB
- create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = create_mesh_from_volume(geometry_set, params);
+ geometry_set.replace_mesh(mesh);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ });
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without OpenVDB"));
#endif
- params.set_output("Geometry", geometry_set_out);
+ params.set_output("Mesh", std::move(geometry_set));
}
} // namespace blender::nodes