[Bf-blender-cvs] [c39d514a4ea] master: Geometry Nodes: Flip Faces Node

Alan Babu noreply at git.blender.org
Fri Jan 21 16:27:10 CET 2022


Commit: c39d514a4eacd4a883775a3fcd8b5a7d8e8e52cc
Author: Alan Babu
Date:   Fri Jan 21 09:26:40 2022 -0600
Branches: master
https://developer.blender.org/rBc39d514a4eacd4a883775a3fcd8b5a7d8e8e52cc

Geometry Nodes: Flip Faces Node

Currently there is no way to flip normals in geometry nodes. This node
makes that possible by flipping the winding order of selected faces.
The node is purposely not called "Flip Normals", because normals are
derived data, changing them is only a side effect. The real change is
that the vertex and edge indices in the face corners of every selected
polygon are reversed, and face corner attribute data is reversed.

While there are existing utilities to flip a polygon and its custom
data, this node aims to process an attribute's data together instead
of processing all attributes separately for each index.

Differential Revision: https://developer.blender.org/D13809

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

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

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

diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 6bcc263be19..772668cb3fb 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -142,6 +142,7 @@ def mesh_node_items(context):
         yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
 
     yield NodeItem("GeometryNodeDualMesh")
+    yield NodeItem("GeometryNodeFlipFaces")
     yield NodeItem("GeometryNodeMeshBoolean")
     yield NodeItem("GeometryNodeMeshToCurve")
     yield NodeItem("GeometryNodeMeshToPoints")
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 1ee8c91ff3e..ccea76fc24d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1630,6 +1630,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
 #define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147
 #define GEO_NODE_FIELD_AT_INDEX 1148
 #define GEO_NODE_CURVE_PRIMITIVE_ARC 1149
+#define GEO_NODE_FLIP_FACES 1150
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 4bac8c150df..9ee54c9ebeb 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4769,6 +4769,7 @@ static void registerGeometryNodes()
   register_node_type_geo_dual_mesh();
   register_node_type_geo_edge_split();
   register_node_type_geo_field_at_index();
+  register_node_type_geo_flip_faces();
   register_node_type_geo_geometry_to_instance();
   register_node_type_geo_image_texture();
   register_node_type_geo_input_curve_handles();
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 1548ba32abc..ff4036308c6 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -100,6 +100,7 @@ void register_node_type_geo_distribute_points_on_faces(void);
 void register_node_type_geo_dual_mesh(void);
 void register_node_type_geo_edge_split(void);
 void register_node_type_geo_field_at_index(void);
+void register_node_type_geo_flip_faces(void);
 void register_node_type_geo_geometry_to_instance(void);
 void register_node_type_geo_image_texture(void);
 void register_node_type_geo_input_curve_handles(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 1657a924ddb..53d6d64ef84 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -355,6 +355,7 @@ DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh",
 DefNode(GeometryNode, GEO_NODE_FIELD_AT_INDEX, def_geo_field_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Field at Index", "")
 DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
 DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
+DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "")
 DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "")
 DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "")
 DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "")
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 7ce8988a075..37d7843020a 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -118,6 +118,7 @@ set(SRC
   nodes/node_geo_dual_mesh.cc
   nodes/node_geo_edge_split.cc
   nodes/node_geo_field_at_index.cc
+  nodes/node_geo_flip_faces.cc
   nodes/node_geo_geometry_to_instance.cc
   nodes/node_geo_image_texture.cc
   nodes/node_geo_input_curve_handles.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
new file mode 100644
index 00000000000..41970d75dfe
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -0,0 +1,114 @@
+/*
+ * 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 "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_flip_faces_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+  b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+  b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+  b.add_output<decl::Geometry>(N_("Mesh"));
+}
+
+static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
+{
+  GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+  const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+  if (domain_size == 0) {
+    return;
+  }
+  fn::FieldEvaluator evaluator{field_context, domain_size};
+  evaluator.add(selection_field);
+  evaluator.evaluate();
+  const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+
+  Mesh *mesh = component.get_for_write();
+
+  mesh->mloop = (MLoop *)CustomData_duplicate_referenced_layer(
+      &mesh->ldata, CD_MLOOP, mesh->totloop);
+  Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+  MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+
+  for (const int i : selection.index_range()) {
+    const MPoly &poly = polys[selection[i]];
+    int start = poly.loopstart;
+    for (const int j : IndexRange(poly.totloop / 2)) {
+      const int index1 = start + j + 1;
+      const int index2 = start + poly.totloop - j - 1;
+      std::swap(loops[index1].v, loops[index2].v);
+      std::swap(loops[index1 - 1].e, loops[index2].e);
+    }
+  }
+
+  component.attribute_foreach(
+      [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+        if (meta_data.domain == ATTR_DOMAIN_CORNER) {
+          OutputAttribute attribute = component.attribute_try_get_for_output(
+              attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type, nullptr);
+          attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+            using T = decltype(dummy);
+            MutableSpan<T> dst_span = attribute.as_span<T>();
+            for (const int j : selection.index_range()) {
+              const MPoly &poly = polys[selection[j]];
+              dst_span.slice(poly.loopstart + 1, poly.totloop - 1).reverse();
+            }
+          });
+          attribute.save();
+        }
+        return true;
+      });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+  GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+  const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+    if (!geometry_set.has_mesh()) {
+      return;
+    }
+    MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+    mesh_flip_faces(mesh_component, selection_field);
+  });
+
+  params.set_output("Mesh", std::move(geometry_set));
+}
+
+}  // namespace blender::nodes::node_geo_flip_faces_cc
+
+void register_node_type_geo_flip_faces()
+{
+  namespace file_ns = blender::nodes::node_geo_flip_faces_cc;
+
+  static bNodeType ntype;
+
+  geo_node_type_base(&ntype, GEO_NODE_FLIP_FACES, "Flip Faces", NODE_CLASS_GEOMETRY);
+  ntype.geometry_node_execute = file_ns::node_geo_exec;
+  ntype.declare = file_ns::node_declare;
+  nodeRegisterType(&ntype);
+}



More information about the Bf-blender-cvs mailing list