Blender  V3.3
node_geo_volume_to_mesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "DEG_depsgraph_query.h"
4 #ifdef WITH_OPENVDB
5 # include <openvdb/tools/GridTransformer.h>
6 # include <openvdb/tools/VolumeToMesh.h>
7 #endif
8 
9 #include "node_geometry_util.hh"
10 
11 #include "BKE_lib_id.h"
12 #include "BKE_material.h"
13 #include "BKE_mesh.h"
14 #include "BKE_mesh_runtime.h"
15 #include "BKE_volume.h"
16 #include "BKE_volume_to_mesh.hh"
17 
18 #include "DNA_mesh_types.h"
19 #include "DNA_meshdata_types.h"
20 
21 #include "UI_interface.h"
22 #include "UI_resources.h"
23 
25 
27 
29 {
30  b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME);
31  b.add_input<decl::Float>(N_("Voxel Size"))
32  .default_value(0.3f)
33  .min(0.01f)
34  .subtype(PROP_DISTANCE)
35  .make_available([](bNode &node) {
36  node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE;
37  });
38  b.add_input<decl::Float>(N_("Voxel Amount"))
39  .default_value(64.0f)
40  .min(0.0f)
41  .make_available([](bNode &node) {
42  node_storage(node).resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT;
43  });
44  b.add_input<decl::Float>(N_("Threshold"))
45  .default_value(0.1f)
46  .description(N_("Values larger than the threshold are inside the generated mesh"));
47  b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
48  b.add_output<decl::Geometry>(N_("Mesh"));
49 }
50 
51 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
52 {
53  uiLayoutSetPropSep(layout, true);
54  uiLayoutSetPropDecorate(layout, false);
55  uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
56 }
57 
59 {
60  NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
61  data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
62  node->storage = data;
63 }
64 
66 {
67  const NodeGeometryVolumeToMesh &storage = node_storage(*node);
68 
69  bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
70  bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
72  voxel_amount_socket,
73  storage.resolution_mode ==
76  voxel_size_socket,
78 }
79 
80 #ifdef WITH_OPENVDB
81 
82 static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
83 {
84  const NodeGeometryVolumeToMesh &storage = node_storage(params.node());
85 
86  bke::VolumeToMeshResolution resolution;
87  resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
89  resolution.settings.voxel_amount = std::max(params.get_input<float>("Voxel Amount"), 0.0f);
90  }
91  else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
92  resolution.settings.voxel_size = std::max(params.get_input<float>("Voxel Size"), 0.0f);
93  }
94 
95  return resolution;
96 }
97 
98 static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> grids,
99  const float threshold,
100  const float adaptivity,
101  const bke::VolumeToMeshResolution &resolution)
102 {
103  Array<bke::OpenVDBMeshData> mesh_data(grids.size());
104  for (const int i : grids.index_range()) {
105  mesh_data[i] = bke::volume_to_mesh_data(*grids[i], resolution, threshold, adaptivity);
106  }
107 
108  int vert_offset = 0;
109  int poly_offset = 0;
110  int loop_offset = 0;
111  Array<int> vert_offsets(mesh_data.size());
112  Array<int> poly_offsets(mesh_data.size());
113  Array<int> loop_offsets(mesh_data.size());
114  for (const int i : grids.index_range()) {
115  const bke::OpenVDBMeshData &data = mesh_data[i];
116  vert_offsets[i] = vert_offset;
117  poly_offsets[i] = poly_offset;
118  loop_offsets[i] = loop_offset;
119  vert_offset += data.verts.size();
120  poly_offset += (data.tris.size() + data.quads.size());
121  loop_offset += (3 * data.tris.size() + 4 * data.quads.size());
122  }
123 
124  Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, 0, loop_offset, poly_offset);
126  MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
127  MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
128  MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
129 
130  for (const int i : grids.index_range()) {
131  const bke::OpenVDBMeshData &data = mesh_data[i];
132  bke::fill_mesh_from_openvdb_data(data.verts,
133  data.tris,
134  data.quads,
135  vert_offsets[i],
136  poly_offsets[i],
137  loop_offsets[i],
138  verts,
139  polys,
140  loops);
141  }
142 
143  BKE_mesh_calc_edges(mesh, false, false);
144 
145  return mesh;
146 }
147 
148 static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParams &params)
149 {
150  const Volume *volume = geometry_set.get_volume_for_read();
151  if (volume == nullptr) {
152  return nullptr;
153  }
154 
155  const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
156 
157  if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE &&
158  resolution.settings.voxel_size <= 0.0f) {
159  return nullptr;
160  }
161  if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT &&
162  resolution.settings.voxel_amount <= 0) {
163  return nullptr;
164  }
165 
166  const Main *bmain = DEG_get_bmain(params.depsgraph());
167  BKE_volume_load(volume, bmain);
168 
169  Vector<openvdb::GridBase::ConstPtr> grids;
170  for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
171  const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
172  openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
173  grids.append(std::move(grid));
174  }
175 
176  if (grids.is_empty()) {
177  return nullptr;
178  }
179 
180  return create_mesh_from_volume_grids(grids,
181  params.get_input<float>("Threshold"),
182  params.get_input<float>("Adaptivity"),
183  resolution);
184 }
185 
186 #endif /* WITH_OPENVDB */
187 
189 {
190  GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
191 
192 #ifdef WITH_OPENVDB
193  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
194  Mesh *mesh = create_mesh_from_volume(geometry_set, params);
195  geometry_set.replace_mesh(mesh);
197  });
198 #else
199  params.error_message_add(NodeWarningType::Error,
200  TIP_("Disabled, Blender was compiled without OpenVDB"));
201 #endif
202 
203  params.set_output("Mesh", std::move(geometry_set));
204 }
205 
206 } // namespace blender::nodes::node_geo_volume_to_mesh_cc
207 
209 {
210  namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc;
211 
212  static bNodeType ntype;
213 
217  &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
218  node_type_size(&ntype, 170, 120, 700);
223  nodeRegisterType(&ntype);
224 }
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_VOLUME
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(struct ID *id)
Definition: material.c:784
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition: node.cc:4396
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4443
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3664
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define GEO_NODE_VOLUME_TO_MESH
Definition: BKE_node.h:1474
Volume data-block.
const VolumeGrid * BKE_volume_grid_get_for_read(const struct Volume *volume, int grid_index)
int BKE_volume_num_grids(const struct Volume *volume)
bool BKE_volume_load(const struct Volume *volume, const struct Main *bmain)
#define UNUSED(x)
#define TIP_(msgid)
#define IFACE_(msgid)
struct Main * DEG_get_bmain(const Depsgraph *graph)
VolumeToMeshResolutionMode
@ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE
@ VOLUME_TO_MESH_RESOLUTION_MODE_GRID
@ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT
@ SOCK_IN
@ PROP_DISTANCE
Definition: RNA_types.h:149
@ PROP_FACTOR
Definition: RNA_types.h:144
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
OperationNode * node
bNodeTree * ntree
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
static void node_declare(NodeDeclarationBuilder &b)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_volume_to_mesh()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
#define min(a, b)
Definition: sort.c:35
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Volume * get_volume_for_read() const
void keep_only_during_modify(const blender::Span< GeometryComponentType > component_types)
void modify_geometry_sets(ForeachSubGeometryCallback callback)
Definition: BKE_main.h:121
struct MVert * mvert
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
union blender::bke::VolumeToMeshResolution::@78 settings
float max
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480