Blender V4.3
node_geo_mesh_topology_corners_of_face.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 "BLI_array_utils.hh"
6#include "BLI_task.hh"
7
8#include "BKE_mesh.hh"
9
10#include "node_geometry_util.hh"
11
13
15{
16 b.add_input<decl::Int>("Face Index")
17 .implicit_field(implicit_field_inputs::index)
18 .description("The face to retrieve data from. Defaults to the face from the context");
19 b.add_input<decl::Float>("Weights").supports_field().hide_value().description(
20 "Values used to sort the face's corners. Uses indices by default");
21 b.add_input<decl::Int>("Sort Index")
22 .min(0)
23 .supports_field()
24 .description("Which of the sorted corners to output");
25 b.add_output<decl::Int>("Corner Index")
26 .field_source_reference_all()
27 .description("A corner of the face, chosen by the sort index");
28 b.add_output<decl::Int>("Total").field_source().reference_pass({0}).description(
29 "The number of corners in the face");
30}
31
33 const Field<int> face_index_;
34 const Field<int> sort_index_;
35 const Field<float> sort_weight_;
36
37 public:
38 CornersOfFaceInput(Field<int> face_index, Field<int> sort_index, Field<float> sort_weight)
39 : bke::MeshFieldInput(CPPType::get<int>(), "Corner of Face"),
40 face_index_(std::move(face_index)),
41 sort_index_(std::move(sort_index)),
42 sort_weight_(std::move(sort_weight))
43 {
45 }
46
48 const AttrDomain domain,
49 const IndexMask &mask) const final
50 {
51 const OffsetIndices faces = mesh.faces();
52
53 const bke::MeshFieldContext context{mesh, domain};
54 fn::FieldEvaluator evaluator{context, &mask};
55 evaluator.add(face_index_);
56 evaluator.add(sort_index_);
57 evaluator.evaluate();
58 const VArray<int> face_indices = evaluator.get_evaluated<int>(0);
59 const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
60
61 const bke::MeshFieldContext corner_context{mesh, AttrDomain::Corner};
62 fn::FieldEvaluator corner_evaluator{corner_context, mesh.corners_num};
63 corner_evaluator.add(sort_weight_);
64 corner_evaluator.evaluate();
65 const VArray<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0);
66 const bool use_sorting = !all_sort_weights.is_single();
67
68 Array<int> corner_of_face(mask.min_array_size());
69 mask.foreach_segment(GrainSize(1024), [&](const IndexMaskSegment segment) {
70 /* Reuse arrays to avoid allocation. */
71 Array<float> sort_weights;
72 Array<int> sort_indices;
73
74 for (const int selection_i : segment) {
75 const int face_i = face_indices[selection_i];
76 const int index_in_sort = indices_in_sort[selection_i];
77 if (!faces.index_range().contains(face_i)) {
78 corner_of_face[selection_i] = 0;
79 continue;
80 }
81
82 const IndexRange corners = faces[face_i];
83
84 const int index_in_sort_wrapped = mod_i(index_in_sort, corners.size());
85 if (use_sorting) {
86 /* Retrieve the weights for each corner. */
87 sort_weights.reinitialize(corners.size());
88 all_sort_weights.materialize_compressed(IndexMask(corners),
89 sort_weights.as_mutable_span());
90
91 /* Sort a separate array of compressed indices corresponding to the compressed weights.
92 * This allows using `materialize_compressed` to avoid virtual function call overhead
93 * when accessing values in the sort weights. However, it means a separate array of
94 * indices within the compressed array is necessary for sorting. */
95 sort_indices.reinitialize(corners.size());
97 std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
98 return sort_weights[a] < sort_weights[b];
99 });
100 corner_of_face[selection_i] = corners[sort_indices[index_in_sort_wrapped]];
101 }
102 else {
103 corner_of_face[selection_i] = corners[index_in_sort_wrapped];
104 }
105 }
106 });
107
108 return VArray<int>::ForContainer(std::move(corner_of_face));
109 }
110
111 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
112 {
113 face_index_.node().for_each_field_input_recursive(fn);
114 sort_index_.node().for_each_field_input_recursive(fn);
115 sort_weight_.node().for_each_field_input_recursive(fn);
116 }
117
118 uint64_t hash() const final
119 {
120 return 6927982716657;
121 }
122
123 bool is_equal_to(const fn::FieldNode &other) const final
124 {
125 if (const auto *typed = dynamic_cast<const CornersOfFaceInput *>(&other)) {
126 return typed->face_index_ == face_index_ && typed->sort_index_ == sort_index_ &&
127 typed->sort_weight_ == sort_weight_;
128 }
129 return false;
130 }
131
132 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
133 {
134 return AttrDomain::Face;
135 }
136};
137
139 public:
140 CornersOfFaceCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Face Corner Count")
141 {
143 }
144
146 const AttrDomain domain,
147 const IndexMask & /*mask*/) const final
148 {
149 if (domain != AttrDomain::Face) {
150 return {};
151 }
152 const OffsetIndices faces = mesh.faces();
153 return VArray<int>::ForFunc(mesh.faces_num,
154 [faces](const int64_t i) { return faces[i].size(); });
155 }
156
157 uint64_t hash() const final
158 {
159 return 8345908765432698;
160 }
161
162 bool is_equal_to(const fn::FieldNode &other) const final
163 {
164 return dynamic_cast<const CornersOfFaceCountInput *>(&other) != nullptr;
165 }
166
167 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
168 {
169 return AttrDomain::Face;
170 }
171};
172
174{
175 const Field<int> face_index = params.extract_input<Field<int>>("Face Index");
176 if (params.output_is_required("Total")) {
177 params.set_output("Total",
178 Field<int>(std::make_shared<bke::EvaluateAtIndexInput>(
179 face_index,
180 Field<int>(std::make_shared<CornersOfFaceCountInput>()),
181 AttrDomain::Face)));
182 }
183 if (params.output_is_required("Corner Index")) {
184 params.set_output("Corner Index",
185 Field<int>(std::make_shared<CornersOfFaceInput>(
186 face_index,
187 params.extract_input<Field<int>>("Sort Index"),
188 params.extract_input<Field<float>>("Weights"))));
189 }
190}
191
192static void node_register()
193{
194 static blender::bke::bNodeType ntype;
196 &ntype, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, "Corners of Face", NODE_CLASS_INPUT);
198 ntype.declare = node_declare;
200}
202
203} // namespace blender::nodes::node_geo_mesh_topology_corners_of_face_cc
#define NODE_CLASS_INPUT
Definition BKE_node.hh:404
MINLINE int mod_i(int i, int n)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
const T * end() const
Definition BLI_array.hh:314
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
const T * begin() const
Definition BLI_array.hh:310
void materialize_compressed(const IndexMask &mask, MutableSpan< T > r_span) const
static VArray ForContainer(ContainerT container)
static VArray ForFunc(const int64_t size, GetFunc get_func)
int add(GField field, GVArray *varray_ptr)
Definition field.cc:756
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:587
const FieldNode & node() const
Definition FN_field.hh:137
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &) const final
CornersOfFaceInput(Field< int > face_index, Field< int > sort_index, Field< float > sort_weight)
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &mask) const final
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void fill_index_range(MutableSpan< T > span, const T start=0)
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
void index(const bNode &, void *r_value)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
#define min(a, b)
Definition sort.c:32
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
Defines a node type.
Definition BKE_node.hh:218
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
NodeDeclareFunction declare
Definition BKE_node.hh:347