Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Babu <alanaman>2022-01-21 18:26:40 +0300
committerHans Goudey <h.goudey@me.com>2022-01-21 18:26:40 +0300
commitc39d514a4eacd4a883775a3fcd8b5a7d8e8e52cc (patch)
treec1f4e90a3e961eb78a36051ba46305033cd326c9 /source/blender/nodes
parent4251455dcd739bb54c4dda8d9fd64460660e5b5f (diff)
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
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc114
4 files changed, 117 insertions, 0 deletions
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);
+}