Blender V4.3
node_geo_mesh_topology_corners_of_edge.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 "BKE_mesh.hh"
6#include "BKE_mesh_mapping.hh"
7
8#include "BLI_array_utils.hh"
9
10#include "node_geometry_util.hh"
11
13
15{
16 b.add_input<decl::Int>("Edge Index")
17 .implicit_field(implicit_field_inputs::index)
18 .description("The edge to retrieve data from. Defaults to the edge from the context");
19 b.add_input<decl::Float>("Weights").supports_field().hide_value().description(
20 "Values that sort the corners attached to the edge");
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()
28 "A corner of the input edge in its face's winding order, chosen by the sort index");
29 b.add_output<decl::Int>("Total").field_source().reference_pass({0}).description(
30 "The number of faces or corners connected to each edge");
31}
32
34 const Field<int> edge_index_;
35 const Field<int> sort_index_;
36 const Field<float> sort_weight_;
37
38 public:
39 CornersOfEdgeInput(Field<int> edge_index, Field<int> sort_index, Field<float> sort_weight)
40 : bke::MeshFieldInput(CPPType::get<int>(), "Corner of Edge"),
41 edge_index_(std::move(edge_index)),
42 sort_index_(std::move(sort_index)),
43 sort_weight_(std::move(sort_weight))
44 {
46 }
47
49 const AttrDomain domain,
50 const IndexMask &mask) const final
51 {
52 const IndexRange edge_range(mesh.edges_num);
53 Array<int> map_offsets;
54 Array<int> map_indices;
55 const Span<int> corner_edges = mesh.corner_edges();
57 mesh.corner_edges(), mesh.edges_num, map_offsets, map_indices);
58
59 const bke::MeshFieldContext context{mesh, domain};
60 fn::FieldEvaluator evaluator{context, &mask};
61 evaluator.add(edge_index_);
62 evaluator.add(sort_index_);
63 evaluator.evaluate();
64 const VArray<int> edge_indices = evaluator.get_evaluated<int>(0);
65 const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
66
67 const bke::MeshFieldContext corner_context{mesh, AttrDomain::Corner};
68 fn::FieldEvaluator corner_evaluator{corner_context, corner_edges.size()};
69 corner_evaluator.add(sort_weight_);
70 corner_evaluator.evaluate();
71 const VArray<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0);
72 const bool use_sorting = !all_sort_weights.is_single();
73
74 Array<int> corner_of_edge(mask.min_array_size());
75 mask.foreach_segment(GrainSize(1024), [&](const IndexMaskSegment segment) {
76 /* Reuse arrays to avoid allocation. */
77 Array<int64_t> corner_indices;
78 Array<float> sort_weights;
79 Array<int> sort_indices;
80
81 for (const int selection_i : segment) {
82 const int edge_i = edge_indices[selection_i];
83 const int index_in_sort = indices_in_sort[selection_i];
84 if (!edge_range.contains(edge_i)) {
85 corner_of_edge[selection_i] = 0;
86 continue;
87 }
88
89 const Span<int> corners = edge_to_loop_map[edge_i];
90 if (corners.is_empty()) {
91 corner_of_edge[selection_i] = 0;
92 continue;
93 }
94
95 const int index_in_sort_wrapped = mod_i(index_in_sort, corners.size());
96 if (use_sorting) {
97 /* Retrieve a compressed array of weights for each edge. */
98 sort_weights.reinitialize(corners.size());
99 IndexMaskMemory memory;
100 all_sort_weights.materialize_compressed(IndexMask::from_indices<int>(corners, memory),
101 sort_weights.as_mutable_span());
102
103 /* Sort a separate array of compressed indices corresponding to the compressed weights.
104 * This allows using `materialize_compressed` to avoid virtual function call overhead
105 * when accessing values in the sort weights. However, it means a separate array of
106 * indices within the compressed array is necessary for sorting. */
107 sort_indices.reinitialize(corners.size());
109 std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
110 return sort_weights[a] < sort_weights[b];
111 });
112 corner_of_edge[selection_i] = corners[sort_indices[index_in_sort_wrapped]];
113 }
114 else {
115 corner_of_edge[selection_i] = corners[index_in_sort_wrapped];
116 }
117 }
118 });
119
120 return VArray<int>::ForContainer(std::move(corner_of_edge));
121 }
122
123 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
124 {
125 edge_index_.node().for_each_field_input_recursive(fn);
126 sort_index_.node().for_each_field_input_recursive(fn);
127 sort_weight_.node().for_each_field_input_recursive(fn);
128 }
129
130 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
131 {
132 return AttrDomain::Edge;
133 }
134};
135
137 public:
138 CornersOfEdgeCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Edge Corner Count")
139 {
141 }
142
144 const AttrDomain domain,
145 const IndexMask & /*mask*/) const final
146 {
147 if (domain != AttrDomain::Edge) {
148 return {};
149 }
150 Array<int> counts(mesh.edges_num, 0);
151 array_utils::count_indices(mesh.corner_edges(), counts);
152 return VArray<int>::ForContainer(std::move(counts));
153 }
154
155 uint64_t hash() const final
156 {
157 return 2345897985577;
158 }
159
160 bool is_equal_to(const fn::FieldNode &other) const final
161 {
162 return dynamic_cast<const CornersOfEdgeCountInput *>(&other) != nullptr;
163 }
164
165 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
166 {
167 return AttrDomain::Edge;
168 }
169};
170
172{
173 const Field<int> edge_index = params.extract_input<Field<int>>("Edge Index");
174 if (params.output_is_required("Total")) {
175 params.set_output("Total",
176 Field<int>(std::make_shared<bke::EvaluateAtIndexInput>(
177 edge_index,
178 Field<int>(std::make_shared<CornersOfEdgeCountInput>()),
179 AttrDomain::Edge)));
180 }
181 if (params.output_is_required("Corner Index")) {
182 params.set_output("Corner Index",
183 Field<int>(std::make_shared<CornersOfEdgeInput>(
184 edge_index,
185 params.extract_input<Field<int>>("Sort Index"),
186 params.extract_input<Field<float>>("Weights"))));
187 }
188}
189
190static void node_register()
191{
192 static blender::bke::bNodeType ntype;
194 &ntype, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_EDGE, "Corners of Edge", NODE_CLASS_INPUT);
196 ntype.declare = node_declare;
198}
200
201} // namespace blender::nodes::node_geo_mesh_topology_corners_of_edge_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
constexpr bool contains(int64_t value) const
constexpr int64_t size() const
Definition BLI_span.hh:253
void materialize_compressed(const IndexMask &mask, MutableSpan< T > r_span) const
static VArray ForContainer(ContainerT container)
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
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &) const final
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &mask) const final
CornersOfEdgeInput(Field< int > edge_index, Field< int > sort_index, Field< float > sort_weight)
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
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 count_indices(Span< int > indices, MutableSpan< int > counts)
void fill_index_range(MutableSpan< T > span, const T start=0)
GroupedSpan< int > build_edge_to_corner_map(Span< int > corner_edges, int edges_num, Array< int > &r_offsets, Array< int > &r_indices)
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
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