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:
authorHans Goudey <h.goudey@me.com>2021-10-26 19:25:44 +0300
committerHans Goudey <h.goudey@me.com>2021-10-26 19:25:44 +0300
commit8ddfdfd2b2a52f746312246aa3099ab0df8544a0 (patch)
tree5b228cb84c3587661a9c5b59878ebc6f99f07dd5 /source/blender/nodes
parent7979dff9dc7985cebb530c7490dc730d9c1acf1d (diff)
Geometry Nodes: Handle multiple grids in the volume to mesh node
In future use cases, a volume can contain many grids that represent the density information. In this case, it's better if the volume to mesh node creates a mesh based on all of the grids in the volume. This is also a benefit to share-ability, since one doesn't have to specify the grid name in the node. Instead, in the future we can have a way to split particular grids into separate volumes, if only one grid should be considered. The code changes are relatively simple: - Move the old volume to mesh node to the legacy folder. - Run the volume to mesh node on all instance geometry, like elsewhere. - Make the blenkernel's volume to mesh API a bit more specific. Differential Revision: https://developer.blender.org/D12997
Diffstat (limited to 'source/blender/nodes')
-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
5 files changed, 260 insertions, 44 deletions
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