Blender V4.3
node_geo_volume_to_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#ifdef WITH_OPENVDB
6# include <openvdb/tools/GridTransformer.h>
7# include <openvdb/tools/VolumeToMesh.h>
8#endif
9
10#include "node_geometry_util.hh"
11
12#include "BKE_material.h"
13#include "BKE_mesh.hh"
14#include "BKE_volume.hh"
15#include "BKE_volume_grid.hh"
16#include "BKE_volume_to_mesh.hh"
17
18#include "NOD_rna_define.hh"
19
20#include "UI_interface.hh"
21#include "UI_resources.hh"
22
23#include "GEO_randomize.hh"
24
26
28
30{
31 b.add_input<decl::Geometry>("Volume")
32 .supported_type(GeometryComponent::Type::Volume)
34 auto &voxel_size = b.add_input<decl::Float>("Voxel Size")
35 .default_value(0.3f)
36 .min(0.01f)
38 .make_available([](bNode &node) {
39 node_storage(node).resolution_mode =
41 });
42 auto &voxel_amount = b.add_input<decl::Float>("Voxel Amount")
43 .default_value(64.0f)
44 .min(0.0f)
45 .make_available([](bNode &node) {
46 node_storage(node).resolution_mode =
48 });
49 b.add_input<decl::Float>("Threshold")
50 .default_value(0.1f)
51 .description("Values larger than the threshold are inside the generated mesh");
52 b.add_input<decl::Float>("Adaptivity").min(0.0f).max(1.0f).subtype(PROP_FACTOR);
53 b.add_output<decl::Geometry>("Mesh");
54
55 const bNode *node = b.node_or_null();
56 if (node != nullptr) {
57 const NodeGeometryVolumeToMesh &storage = node_storage(*node);
58
59 voxel_size.available(storage.resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
60 voxel_amount.available(storage.resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT);
61 }
62}
63
64static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
65{
66 uiLayoutSetPropSep(layout, true);
67 uiLayoutSetPropDecorate(layout, false);
68 uiItemR(layout, ptr, "resolution_mode", UI_ITEM_NONE, IFACE_("Resolution"), ICON_NONE);
69}
70
71static void node_init(bNodeTree * /*tree*/, bNode *node)
72{
73 NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
74 data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
75 node->storage = data;
76}
77
78#ifdef WITH_OPENVDB
79
80static bke::VolumeToMeshResolution get_resolution_param(const GeoNodeExecParams &params)
81{
82 const NodeGeometryVolumeToMesh &storage = node_storage(params.node());
83
86 if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
87 resolution.settings.voxel_amount = std::max(params.get_input<float>("Voxel Amount"), 0.0f);
88 }
89 else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
90 resolution.settings.voxel_size = std::max(params.get_input<float>("Voxel Size"), 0.0f);
91 }
92
93 return resolution;
94}
95
96static Mesh *create_mesh_from_volume_grids(Span<const openvdb::GridBase *> grids,
97 GeoNodeExecParams &params,
98 const float threshold,
99 const float adaptivity,
100 const bke::VolumeToMeshResolution &resolution)
101{
102 Array<bke::VolumeToMeshDataResult> mesh_data(grids.size());
103 for (const int i : grids.index_range()) {
104 bke::VolumeToMeshDataResult &result = mesh_data[i];
105 result = bke::volume_to_mesh_data(*grids[i], resolution, threshold, adaptivity);
106 if (!result.error.empty()) {
107 params.error_message_add(NodeWarningType::Error, result.error);
108 }
109 }
110
111 int vert_offset = 0;
112 int face_offset = 0;
113 int loop_offset = 0;
114 Array<int> vert_offsets(mesh_data.size());
115 Array<int> face_offsets(mesh_data.size());
116 Array<int> loop_offsets(mesh_data.size());
117 for (const int i : grids.index_range()) {
118 const bke::OpenVDBMeshData &data = mesh_data[i].data;
119 vert_offsets[i] = vert_offset;
120 face_offsets[i] = face_offset;
121 loop_offsets[i] = loop_offset;
122 vert_offset += data.verts.size();
123 face_offset += (data.tris.size() + data.quads.size());
124 loop_offset += (3 * data.tris.size() + 4 * data.quads.size());
125 }
126
127 Mesh *mesh = BKE_mesh_new_nomain(vert_offset, 0, face_offset, loop_offset);
129 MutableSpan<float3> positions = mesh->vert_positions_for_write();
130 MutableSpan<int> dst_face_offsets = mesh->face_offsets_for_write();
131 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
132
133 for (const int i : grids.index_range()) {
134 const bke::OpenVDBMeshData &data = mesh_data[i].data;
135 bke::fill_mesh_from_openvdb_data(data.verts,
136 data.tris,
137 data.quads,
138 vert_offsets[i],
139 face_offsets[i],
140 loop_offsets[i],
141 positions,
142 dst_face_offsets,
143 corner_verts);
144 }
145
146 bke::mesh_calc_edges(*mesh, false, false);
147 bke::mesh_smooth_set(*mesh, false);
148
149 mesh->tag_overlapping_none();
150
152
153 return mesh;
154}
155
156static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParams &params)
157{
158 const Volume *volume = geometry_set.get_volume();
159 if (volume == nullptr) {
160 return nullptr;
161 }
162
163 const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
164
165 if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE &&
166 resolution.settings.voxel_size <= 0.0f)
167 {
168 return nullptr;
169 }
170 if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT &&
171 resolution.settings.voxel_amount <= 0)
172 {
173 return nullptr;
174 }
175
176 BKE_volume_load(volume, params.bmain());
177
178 Vector<bke::VolumeTreeAccessToken> tree_tokens;
179 Vector<const openvdb::GridBase *> grids;
180 for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
181 const bke::VolumeGridData *volume_grid = BKE_volume_grid_get(volume, i);
182 tree_tokens.append_as();
183 grids.append(&volume_grid->grid(tree_tokens.last()));
184 }
185
186 if (grids.is_empty()) {
187 return nullptr;
188 }
189
190 return create_mesh_from_volume_grids(grids,
191 params,
192 params.get_input<float>("Threshold"),
193 params.get_input<float>("Adaptivity"),
194 resolution);
195}
196
197#endif /* WITH_OPENVDB */
198
200{
201#ifdef WITH_OPENVDB
202 GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
203 geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
204 Mesh *mesh = create_mesh_from_volume(geometry_set, params);
205 geometry_set.replace_mesh(mesh);
207 });
208 params.set_output("Mesh", std::move(geometry_set));
209#else
211#endif
212}
213
214static void node_rna(StructRNA *srna)
215{
216 static EnumPropertyItem resolution_mode_items[] = {
218 "GRID",
219 0,
220 "Grid",
221 "Use resolution of the volume grid"},
223 "VOXEL_AMOUNT",
224 0,
225 "Amount",
226 "Desired number of voxels along one axis"},
228 "VOXEL_SIZE",
229 0,
230 "Size",
231 "Desired voxel side length"},
232 {0, nullptr, 0, nullptr, nullptr},
233 };
234
236 "resolution_mode",
237 "Resolution Mode",
238 "How the voxel size is specified",
239 resolution_mode_items,
240 NOD_storage_enum_accessors(resolution_mode));
241}
242
243static void node_register()
244{
245 static blender::bke::bNodeType ntype;
246
247 geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY);
248 ntype.declare = node_declare;
250 &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
251 blender::bke::node_type_size(&ntype, 170, 120, 700);
252 ntype.initfunc = node_init;
256
257 node_rna(ntype.rna_ext.srna);
258}
260
261} // namespace blender::nodes::node_geo_volume_to_mesh_cc
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(struct ID *id)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:418
Volume data-block.
int BKE_volume_num_grids(const Volume *volume)
bool BKE_volume_load(const Volume *volume, const Main *bmain)
const blender::bke::VolumeGridData * BKE_volume_grid_get(const Volume *volume, int grid_index)
#define BLT_I18NCONTEXT_ID_ID
#define IFACE_(msgid)
VolumeToMeshResolutionMode
@ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE
@ VOLUME_TO_MESH_RESOLUTION_MODE_GRID
@ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
@ PROP_DISTANCE
Definition RNA_types.hh:159
@ PROP_FACTOR
Definition RNA_types.hh:154
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
void make_available(bNode &node) const
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void mesh_smooth_set(Mesh &mesh, bool use_smooth, bool keep_sharp_edges=false)
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges)
void node_type_size(bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition node.cc:4602
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:220
static void node_declare(NodeDeclarationBuilder &b)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *, bNode *node)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
void node_geo_exec_with_missing_openvdb(GeoNodeExecParams &params)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
#define min(a, b)
Definition sort.c:32
StructRNA * srna
Definition RNA_types.hh:780
void keep_only_during_modify(Span< GeometryComponent::Type > component_types)
void modify_geometry_sets(ForeachSubGeometryCallback callback)
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126