Blender V4.3
node_geo_mesh_topology_edges_of_vertex.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>("Vertex Index")
17 .implicit_field(implicit_field_inputs::index)
18 .description("The vertex to retrieve data from. Defaults to the vertex from the context");
19 b.add_input<decl::Float>("Weights").supports_field().hide_value().description(
20 "Values used to sort the edges connected to the vertex. Uses indices by default");
21 b.add_input<decl::Int>("Sort Index")
22 .min(0)
23 .supports_field()
24 .description("Which of the sorted edges to output");
25 b.add_output<decl::Int>("Edge Index")
26 .field_source_reference_all()
27 .description("An edge connected to the face, chosen by the sort index");
28 b.add_output<decl::Int>("Total").field_source().reference_pass({0}).description(
29 "The number of edges connected to each vertex");
30}
31
33 const Field<int> vert_index_;
34 const Field<int> sort_index_;
35 const Field<float> sort_weight_;
36
37 public:
38 EdgesOfVertInput(Field<int> vert_index, Field<int> sort_index, Field<float> sort_weight)
39 : bke::MeshFieldInput(CPPType::get<int>(), "Edge of Vertex"),
40 vert_index_(std::move(vert_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 IndexRange vert_range(mesh.verts_num);
52 const Span<int2> edges = mesh.edges();
53 Array<int> map_offsets;
54 Array<int> map_indices;
56 edges, mesh.verts_num, map_offsets, map_indices);
57
58 const bke::MeshFieldContext context{mesh, domain};
59 fn::FieldEvaluator evaluator{context, &mask};
60 evaluator.add(vert_index_);
61 evaluator.add(sort_index_);
62 evaluator.evaluate();
63 const VArray<int> vert_indices = evaluator.get_evaluated<int>(0);
64 const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
65
66 const bke::MeshFieldContext edge_context{mesh, AttrDomain::Edge};
67 fn::FieldEvaluator edge_evaluator{edge_context, mesh.edges_num};
68 edge_evaluator.add(sort_weight_);
69 edge_evaluator.evaluate();
70 const VArray<float> all_sort_weights = edge_evaluator.get_evaluated<float>(0);
71 const bool use_sorting = !all_sort_weights.is_single();
72
73 Array<int> edge_of_vertex(mask.min_array_size());
74 mask.foreach_segment(GrainSize(1024), [&](const IndexMaskSegment segment) {
75 /* Reuse arrays to avoid allocation. */
76 Array<float> sort_weights;
77 Array<int> sort_indices;
78
79 for (const int selection_i : segment) {
80 const int vert_i = vert_indices[selection_i];
81 const int index_in_sort = indices_in_sort[selection_i];
82 if (!vert_range.contains(vert_i)) {
83 edge_of_vertex[selection_i] = 0;
84 continue;
85 }
86
87 const Span<int> edges = vert_to_edge_map[vert_i];
88 if (edges.is_empty()) {
89 edge_of_vertex[selection_i] = 0;
90 continue;
91 }
92
93 const int index_in_sort_wrapped = mod_i(index_in_sort, edges.size());
94 if (use_sorting) {
95 /* Retrieve a compressed array of weights for each edge. */
96 sort_weights.reinitialize(edges.size());
97 IndexMaskMemory memory;
98 all_sort_weights.materialize_compressed(IndexMask::from_indices<int>(edges, memory),
99 sort_weights.as_mutable_span());
100
101 /* Sort a separate array of compressed indices corresponding to the compressed weights.
102 * This allows using `materialize_compressed` to avoid virtual function call overhead
103 * when accessing values in the sort weights. However, it means a separate array of
104 * indices within the compressed array is necessary for sorting. */
105 sort_indices.reinitialize(edges.size());
107 std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
108 return sort_weights[a] < sort_weights[b];
109 });
110
111 edge_of_vertex[selection_i] = edges[sort_indices[index_in_sort_wrapped]];
112 }
113 else {
114 edge_of_vertex[selection_i] = edges[index_in_sort_wrapped];
115 }
116 }
117 });
118
119 return VArray<int>::ForContainer(std::move(edge_of_vertex));
120 }
121
122 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
123 {
124 vert_index_.node().for_each_field_input_recursive(fn);
125 sort_index_.node().for_each_field_input_recursive(fn);
126 sort_weight_.node().for_each_field_input_recursive(fn);
127 }
128
129 uint64_t hash() const final
130 {
131 return 98762349875636;
132 }
133
134 bool is_equal_to(const fn::FieldNode &other) const final
135 {
136 if (const auto *typed = dynamic_cast<const EdgesOfVertInput *>(&other)) {
137 return typed->vert_index_ == vert_index_ && typed->sort_index_ == sort_index_ &&
138 typed->sort_weight_ == sort_weight_;
139 }
140 return false;
141 }
142
143 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
144 {
145 return AttrDomain::Point;
146 }
147};
148
150 public:
151 EdgesOfVertCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Face Index")
152 {
154 }
155
157 const AttrDomain domain,
158 const IndexMask & /*mask*/) const final
159 {
160 if (domain != AttrDomain::Point) {
161 return {};
162 }
163 Array<int> counts(mesh.verts_num, 0);
164 array_utils::count_indices(mesh.edges().cast<int>(), counts);
165 return VArray<int>::ForContainer(std::move(counts));
166 }
167
168 uint64_t hash() const final
169 {
170 return 436758278618374;
171 }
172
173 bool is_equal_to(const fn::FieldNode &other) const final
174 {
175 return dynamic_cast<const EdgesOfVertCountInput *>(&other) != nullptr;
176 }
177
178 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const final
179 {
180 return AttrDomain::Point;
181 }
182};
183
185{
186 const Field<int> vert_index = params.extract_input<Field<int>>("Vertex Index");
187 if (params.output_is_required("Total")) {
188 params.set_output("Total",
189 Field<int>(std::make_shared<bke::EvaluateAtIndexInput>(
190 vert_index,
191 Field<int>(std::make_shared<EdgesOfVertCountInput>()),
192 AttrDomain::Point)));
193 }
194 if (params.output_is_required("Edge Index")) {
195 params.set_output("Edge Index",
196 Field<int>(std::make_shared<EdgesOfVertInput>(
197 vert_index,
198 params.extract_input<Field<int>>("Sort Index"),
199 params.extract_input<Field<float>>("Weights"))));
200 }
201}
202
203static void node_register()
204{
205 static blender::bke::bNodeType ntype;
207 &ntype, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX, "Edges of Vertex", NODE_CLASS_INPUT);
209 ntype.declare = node_declare;
211}
213
214} // namespace blender::nodes::node_geo_mesh_topology_edges_of_vertex_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
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
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
EdgesOfVertInput(Field< int > vert_index, Field< int > sort_index, Field< float > sort_weight)
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_vert_to_edge_map(Span< int2 > edges, int verts_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