Blender V5.0
node_geo_input_mesh_face_is_planar.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#include <algorithm>
6
7#include "BLI_math_vector.hh"
8
9#include "DNA_mesh_types.h"
10
11#include "node_geometry_util.hh"
12
14
16{
17 b.add_input<decl::Float>("Threshold")
18 .default_value(0.01f)
19 .min(0.0f)
21 .supports_field()
22 .description(
23 "The distance a point can be from the surface before the face is no longer "
24 "considered planar");
25 b.add_output<decl::Bool>("Planar")
26 .translation_context(BLT_I18NCONTEXT_ID_NODETREE)
27 .field_source();
28}
29
31 private:
32 Field<float> threshold_;
33
34 public:
36 : bke::MeshFieldInput(CPPType::get<bool>(), "Planar"), threshold_(threshold)
37 {
39 }
40
42 const AttrDomain domain,
43 const IndexMask & /*mask*/) const final
44 {
45 const Span<float3> positions = mesh.vert_positions();
46 const OffsetIndices faces = mesh.faces();
47 const Span<int> corner_verts = mesh.corner_verts();
48 const Span<float3> face_normals = mesh.face_normals();
49
50 const bke::MeshFieldContext context{mesh, AttrDomain::Face};
51 fn::FieldEvaluator evaluator{context, faces.size()};
52 evaluator.add(threshold_);
53 evaluator.evaluate();
54 const VArray<float> thresholds = evaluator.get_evaluated<float>(0);
55
56 auto planar_fn =
57 [positions, faces, corner_verts, thresholds, face_normals](const int i) -> bool {
58 const IndexRange face = faces[i];
59 if (face.size() <= 3) {
60 return true;
61 }
62 const float3 &reference_normal = face_normals[i];
63
64 float min = FLT_MAX;
65 float max = -FLT_MAX;
66
67 for (const int vert : corner_verts.slice(face)) {
68 float dot = math::dot(reference_normal, positions[vert]);
69 max = std::max(dot, max);
70 min = std::min(dot, min);
71 }
72 return max - min < thresholds[i] / 2.0f;
73 };
74
75 return mesh.attributes().adapt_domain<bool>(
76 VArray<bool>::from_func(faces.size(), planar_fn), AttrDomain::Face, domain);
77 }
78
79 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
80 {
81 threshold_.node().for_each_field_input_recursive(fn);
82 }
83
84 uint64_t hash() const override
85 {
86 /* Some random constant hash. */
87 return 2356235652;
88 }
89
90 bool is_equal_to(const fn::FieldNode &other) const override
91 {
92 return dynamic_cast<const PlanarFieldInput *>(&other) != nullptr;
93 }
94
95 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
96 {
97 return AttrDomain::Face;
98 }
99};
100
102{
103 Field<float> threshold = params.extract_input<Field<float>>("Threshold");
104 Field<bool> planar_field{std::make_shared<PlanarFieldInput>(threshold)};
105 params.set_output("Planar", std::move(planar_field));
106}
107
108static void node_register()
109{
110 static blender::bke::bNodeType ntype;
111
113 &ntype, "GeometryNodeInputMeshFaceIsPlanar", GEO_NODE_INPUT_MESH_FACE_IS_PLANAR);
114 ntype.ui_name = "Is Face Planar";
115 ntype.ui_description =
116 "Retrieve whether all triangles in a face are on the same plane, i.e. whether they have the "
117 "same normal";
118 ntype.enum_name_legacy = "MESH_FACE_IS_PLANAR";
119 ntype.nclass = NODE_CLASS_INPUT;
121 ntype.declare = node_declare;
123}
125
126} // namespace blender::nodes::node_geo_input_mesh_face_is_planar_cc
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define GEO_NODE_INPUT_MESH_FACE_IS_PLANAR
#define final(a, b, c)
Definition BLI_hash.h:19
#define BLT_I18NCONTEXT_ID_NODETREE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_DISTANCE
Definition RNA_types.hh:256
unsigned long long int uint64_t
constexpr int64_t size() const
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
static VArray from_func(const int64_t size, GetFunc get_func)
FieldInput(const CPPType &type, std::string debug_name="")
Definition field.cc:677
int add(GField field, GVArray *varray_ptr)
Definition field.cc:751
const GVArray & get_evaluated(const int field_index) const
Definition FN_field.hh:448
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &) const final
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char faces[256]
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251