Blender  V3.3
node_geo_boolean.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "DNA_mesh_types.h"
4 
7 
8 #include "UI_interface.h"
9 #include "UI_resources.h"
10 
11 #include "node_geometry_util.hh"
12 
14 
16 {
17  b.add_input<decl::Geometry>(N_("Mesh 1"))
18  .only_realized_data()
19  .supported_type(GEO_COMPONENT_TYPE_MESH);
20  b.add_input<decl::Geometry>(N_("Mesh 2")).multi_input().supported_type(GEO_COMPONENT_TYPE_MESH);
21  b.add_input<decl::Bool>(N_("Self Intersection"));
22  b.add_input<decl::Bool>(N_("Hole Tolerant"));
23  b.add_output<decl::Geometry>(N_("Mesh"));
24  b.add_output<decl::Bool>(N_("Intersecting Edges")).field_source();
25 }
26 
27 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
28 {
29  uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
30 }
31 
34 };
35 
37 {
39 
40  bNodeSocket *geometry_1_socket = (bNodeSocket *)node->inputs.first;
41  bNodeSocket *geometry_2_socket = geometry_1_socket->next;
42 
43  switch (operation) {
46  nodeSetSocketAvailability(ntree, geometry_1_socket, false);
47  nodeSetSocketAvailability(ntree, geometry_2_socket, true);
48  node_sock_label(geometry_2_socket, N_("Mesh"));
49  break;
51  nodeSetSocketAvailability(ntree, geometry_1_socket, true);
52  nodeSetSocketAvailability(ntree, geometry_2_socket, true);
53  node_sock_label(geometry_2_socket, N_("Mesh 2"));
54  break;
55  }
56 }
57 
59 {
61 }
62 
64 {
65 #ifdef WITH_GMP
67  const bool use_self = params.get_input<bool>("Self Intersection");
68  const bool hole_tolerant = params.get_input<bool>("Hole Tolerant");
69 
70  Vector<const Mesh *> meshes;
71  Vector<const float4x4 *> transforms;
72 
74  Vector<Array<short>> material_remaps;
75 
76  GeometrySet set_a;
77  if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
78  set_a = params.extract_input<GeometrySet>("Mesh 1");
79  /* Note that it technically wouldn't be necessary to realize the instances for the first
80  * geometry input, but the boolean code expects the first shape for the difference operation
81  * to be a single mesh. */
82  const Mesh *mesh_in_a = set_a.get_mesh_for_read();
83  if (mesh_in_a != nullptr) {
84  meshes.append(mesh_in_a);
85  transforms.append(nullptr);
86  for (Material *material : Span(mesh_in_a->mat, mesh_in_a->totcol)) {
87  materials.add(material);
88  }
89  material_remaps.append({});
90  }
91  }
92 
93  /* The instance transform matrices are owned by the instance group, so we have to
94  * keep all of them around for use during the boolean operation. */
96  Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Mesh 2");
97  for (const GeometrySet &geometry_set : geometry_sets) {
98  bke::geometry_set_gather_instances(geometry_set, set_groups);
99  }
100 
101  for (const bke::GeometryInstanceGroup &set_group : set_groups) {
102  const Mesh *mesh = set_group.geometry_set.get_mesh_for_read();
103  if (mesh != nullptr) {
104  for (Material *material : Span(mesh->mat, mesh->totcol)) {
105  materials.add(material);
106  }
107  }
108  }
109  for (const bke::GeometryInstanceGroup &set_group : set_groups) {
110  const Mesh *mesh = set_group.geometry_set.get_mesh_for_read();
111  if (mesh != nullptr) {
113  for (const int i : IndexRange(mesh->totcol)) {
114  map[i] = materials.index_of(mesh->mat[i]);
115  }
116  material_remaps.append(std::move(map));
117  }
118  }
119 
120  for (const bke::GeometryInstanceGroup &set_group : set_groups) {
121  const Mesh *mesh_in = set_group.geometry_set.get_mesh_for_read();
122  if (mesh_in != nullptr) {
123  meshes.append_n_times(mesh_in, set_group.transforms.size());
124  for (const int i : set_group.transforms.index_range()) {
125  transforms.append(set_group.transforms.begin() + i);
126  }
127  }
128  }
129 
130  AttributeOutputs attribute_outputs;
131  if (params.output_is_required("Intersecting Edges")) {
132  attribute_outputs.intersecting_edges_id = StrongAnonymousAttributeID("Intersecting Edges");
133  }
134 
135  Vector<int> intersecting_edges;
137  meshes,
138  transforms,
140  material_remaps,
141  use_self,
142  hole_tolerant,
143  operation,
144  attribute_outputs.intersecting_edges_id ? &intersecting_edges : nullptr);
145  if (!result) {
146  params.set_default_remaining_outputs();
147  return;
148  }
149 
150  MEM_SAFE_FREE(result->mat);
151  result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
152  result->totcol = materials.size();
153  MutableSpan(result->mat, result->totcol).copy_from(materials);
154 
155  /* Store intersecting edges in attribute. */
156  if (attribute_outputs.intersecting_edges_id) {
159  attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE);
160 
161  selection.span.fill(false);
162  for (const int i : intersecting_edges) {
163  selection.span[i] = true;
164  }
165  selection.finish();
166 
167  params.set_output(
168  "Intersecting Edges",
169  AnonymousAttributeFieldInput::Create<bool>(
170  std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name()));
171  }
172 
173  params.set_output("Mesh", GeometrySet::create_with_mesh(result));
174 #else
175  params.error_message_add(NodeWarningType::Error,
176  TIP_("Disabled, Blender was compiled without GMP"));
177  params.set_default_remaining_outputs();
178 #endif
179 }
180 
181 } // namespace blender::nodes::node_geo_boolean_cc
182 
184 {
185  namespace file_ns = blender::nodes::node_geo_boolean_cc;
186 
187  static bNodeType ntype;
188 
195  nodeRegisterType(&ntype);
196 }
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:28
@ GEO_COMPONENT_TYPE_MESH
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 GEO_NODE_MESH_BOOLEAN
Definition: BKE_node.h:1385
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define UNUSED(x)
#define TIP_(msgid)
GeometryNodeBooleanOperation
@ GEO_NODE_BOOLEAN_DIFFERENCE
@ GEO_NODE_BOOLEAN_UNION
@ GEO_NODE_BOOLEAN_INTERSECT
#define MEM_SAFE_FREE(v)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
constexpr void copy_from(Span< T > values)
Definition: BLI_span.hh:707
void append(const T &value)
Definition: BLI_vector.hh:433
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
OperationNode * node
Material material
void * tree
bNodeTree * ntree
smooth(Type::VEC4, "color_mul") .smooth(Type gpFillTexture gpSceneDepthTexture materials[GPENCIL_MATERIAL_BUFFER_LEN]
Definition: gpencil_info.hh:29
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void geometry_set_gather_instances(const GeometrySet &geometry_set, Vector< GeometryInstanceGroup > &r_instance_groups)
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
OwnedAnonymousAttributeID< true > StrongAnonymousAttributeID
Mesh * direct_mesh_boolean(Span< const Mesh * > meshes, Span< const float4x4 * > transforms, const float4x4 &target_transform, Span< Array< short >> material_remaps, bool use_self, bool hole_tolerant, int boolean_mode, Vector< int > *r_intersecting_edges)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_update(bNodeTree *ntree, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
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_boolean()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
SocketIndexByIdentifierMap * map
void node_sock_label(bNodeSocket *sock, const char *name)
Definition: node_util.c:76
static GeometrySet create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Mesh * get_mesh_for_read() const
float size[3]
struct Material ** mat
short totcol
struct bNodeSocket * next
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* updatefunc)(struct bNodeTree *ntree, struct bNode *node)
Definition: BKE_node.h:265
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
static float4x4 identity()
Definition: BLI_float4x4.hh:80
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480