[Bf-blender-cvs] [fe45f565150] geometry-nodes-boolean-node: Geometry nodes: Initial boolean node implementation

Hans Goudey noreply at git.blender.org
Sat Oct 24 19:50:38 CEST 2020


Commit: fe45f565150ce6ad9c67e1396d1dc1cdc920f377
Author: Hans Goudey
Date:   Fri Oct 23 18:14:36 2020 -0500
Branches: geometry-nodes-boolean-node
https://developer.blender.org/rBfe45f565150ce6ad9c67e1396d1dc1cdc920f377

Geometry nodes: Initial boolean node implementation

This is fairly hacky and crashy and should not be the final implementation
of this node, but it's nice to know that the basics are there to support
this kind of functionality. Ideally the boolean code would not need the
conversion to bmesh.

===================================================================

M	release/scripts/startup/nodeitems_builtins.py
M	source/blender/blenkernel/BKE_node.h
M	source/blender/blenkernel/intern/node.c
M	source/blender/nodes/CMakeLists.txt
M	source/blender/nodes/NOD_geometry.h
M	source/blender/nodes/NOD_static_types.h
A	source/blender/nodes/geometry/nodes/node_geo_boolean.cc

===================================================================

diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 82a957fb118..7e79f74b022 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -489,6 +489,7 @@ geometry_node_categories = [
         NodeItem("GeometryNodeTriangulate"),
         NodeItem("GeometryNodeEdgeSplit"),
         NodeItem("GeometryNodeTransform"),
+        NodeItem("GeometryNodeBoolean"),
     ]),
     GeometryNodeCategory("GEO_MATH", "Misc", items=[
         NodeItem("ShaderNodeMapRange"),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 0ae31989a05..4de2db44698 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1343,6 +1343,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
 #define GEO_NODE_TRIANGULATE 1000
 #define GEO_NODE_EDGE_SPLIT 1001
 #define GEO_NODE_TRANSFORM 1002
+#define GEO_NODE_BOOLEAN 1003
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index f7b5e92d11b..e1be00c6a1f 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -4662,6 +4662,7 @@ static void registerGeometryNodes(void)
   register_node_type_geo_triangulate();
   register_node_type_geo_edge_split();
   register_node_type_geo_transform();
+  register_node_type_geo_boolean();
 }
 
 static void registerFunctionNodes(void)
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index ffaabecb406..67b990d0e0f 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
   ../blenkernel
   ../blenlib
   ../blentranslation
+  ../bmesh
   ../depsgraph
   ../functions
   ../gpu
@@ -138,6 +139,7 @@ set(SRC
   function/node_function_util.cc
 
   geometry/nodes/node_geo_common.cc
+  geometry/nodes/node_geo_boolean.cc
   geometry/nodes/node_geo_edge_split.cc
   geometry/nodes/node_geo_transform.cc
   geometry/nodes/node_geo_triangulate.cc
@@ -301,6 +303,7 @@ set(SRC
 set(LIB
   bf_functions
   bf_intern_sky
+  bf_bmesh
 )
 
 if(WITH_PYTHON)
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 27d8f3a898c..329a9620bc5 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -27,6 +27,7 @@ void register_node_tree_type_geo(void);
 void register_node_type_geo_group(void);
 
 void register_node_type_geo_triangulate(void);
+void register_node_type_geo_boolean(void);
 void register_node_type_geo_edge_split(void);
 void register_node_type_geo_transform(void);
 
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 5cfc9148f34..6cff4d03d0c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -269,6 +269,7 @@ DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0,                  "RANDOM_FLOAT",
 DefNode(GeometryNode, GEO_NODE_TRIANGULATE, 0, "TRIANGULATE", Triangulate, "Triangulate", "")
 DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
 DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
+DefNode(GeometryNode, GEO_NODE_BOOLEAN, 0, "BOOLEAN", Boolean, "Boolean", "")
 
 
 /* undefine macros */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
new file mode 100644
index 00000000000..129794f8175
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -0,0 +1,150 @@
+/*
+ * 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 "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_mesh.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math_matrix.h"
+
+#include "bmesh.h"
+#include "tools/bmesh_boolean.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_boolean_in[] = {
+    {SOCK_GEOMETRY, N_("Geometry A")},
+    {SOCK_GEOMETRY, N_("Geometry B")},
+    {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_boolean_out[] = {
+    {SOCK_GEOMETRY, N_("Geometry")},
+    {-1, ""},
+};
+
+static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
+{
+  return BM_elem_flag_test(f, BM_ELEM_DRAW) ? 1 : 0;
+}
+
+static Mesh *BM_mesh_boolean_calc(Mesh *mesh_a, Mesh *mesh_b, int boolean_mode)
+{
+  const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh_a, mesh_b);
+
+  BMesh *bm;
+  {
+    struct BMeshCreateParams bmesh_create_params = {.use_toolflags = false};
+    bm = BM_mesh_create(&allocsize, &bmesh_create_params);
+  }
+
+  {
+    struct BMeshFromMeshParams bmesh_from_mesh_params = {.calc_face_normal = true};
+    BM_mesh_bm_from_me(bm, mesh_a, &bmesh_from_mesh_params);
+
+    BM_mesh_bm_from_me(bm, mesh_b, &bmesh_from_mesh_params);
+  }
+
+  const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+  int tottri;
+  BMLoop *(*looptris)[3];
+  looptris = (BMLoop * (*)[3])(MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__));
+  BM_mesh_calc_tessellation_beauty(bm, looptris, &tottri);
+
+  BMIter iter;
+  int i;
+  const int i_faces_end = mesh_a->totpoly;
+
+  /* We need face normals because of 'BM_face_split_edgenet'
+   * we could calculate on the fly too (before calling split). */
+
+  const short ob_src_totcol = mesh_a->totcol;
+  short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1);
+
+  BMFace *bm_face;
+  i = 0;
+  BM_ITER_MESH (bm_face, &iter, bm, BM_FACES_OF_MESH) {
+    normalize_v3(bm_face->no);
+
+    /* Temp tag to test which side split faces are from. */
+    BM_elem_flag_enable(bm_face, BM_ELEM_DRAW);
+
+    /* Remap material. */
+    if (bm_face->mat_nr < ob_src_totcol) {
+      bm_face->mat_nr = material_remap[bm_face->mat_nr];
+    }
+
+    if (++i == i_faces_end) {
+      break;
+    }
+  }
+
+  BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, false, boolean_mode);
+
+  Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh_a);
+  BM_mesh_free(bm);
+  result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+  return result;
+}
+
+// Mesh *mesh_boolean_calc(Mesh *mesh_a, Mesh *UNUSED(mesh_b), int UNUSED(boolean_mode))
+// {
+//   return mesh_a;
+// }
+
+namespace blender::nodes {
+static void geo_boolean_exec(bNode *UNUSED(node), GValueByName &inputs, GValueByName &outputs)
+{
+  GeometryPtr geometry_in_a = inputs.extract<GeometryPtr>("Geometry A");
+  GeometryPtr geometry_in_b = inputs.extract<GeometryPtr>("Geometry B");
+  GeometryPtr geometry_out;
+
+  if (!geometry_in_a.has_value() || !geometry_in_b.has_value()) {
+    outputs.move_in("Geometry", std::move(geometry_out));
+    return;
+  }
+
+  Mesh *mesh_in_a = geometry_in_a->mesh_get_for_read();
+  Mesh *mesh_in_b = geometry_in_b->mesh_get_for_read();
+  if (mesh_in_a == nullptr || mesh_in_b == nullptr) {
+    outputs.move_in("Geometry", std::move(geometry_out));
+    return;
+  }
+
+  geometry_out = GeometryPtr{new Geometry()};
+
+  Mesh *mesh_out = BM_mesh_boolean_calc(mesh_in_a, mesh_in_b, eBooleanModifierOp_Difference);
+
+  geometry_out->mesh_set_and_transfer_ownership(mesh_out);
+
+  outputs.move_in("Geometry", std::move(geometry_out));
+}
+}  // namespace blender::nodes
+
+void register_node_type_geo_boolean()
+{
+  static bNodeType ntype;
+
+  geo_node_type_base(&ntype, GEO_NODE_BOOLEAN, "Boolean", 0, 0);
+  node_type_socket_templates(&ntype, geo_node_boolean_in, geo_node_boolean_out);
+  ntype.geometry_node_execute = blender::nodes::geo_boolean_exec;
+  nodeRegisterType(&ntype);
+}



More information about the Bf-blender-cvs mailing list