36 const bNode *node =
b.node_or_null();
38 if (node !=
nullptr) {
40 b.add_input(data_type,
"Value").supports_field().hide_value().is_default_link_socket();
45 .
description(
"How many times to blur the values for all elements");
52 .description(
"Relative mix weight of neighboring elements");
54 if (node !=
nullptr) {
56 b.add_output(data_type,
"Value").field_source_reference_all().dependent_field();
80 if (!new_node_type.has_value()) {
100 node.custom1 = fixed_data_type;
101 params.update_and_connect_available_socket(node,
"Value");
113 for (
const int vert :
range) {
130 edges, verts_num, vert_to_edge_offset_data, vert_to_edge_indices);
135 for (const int edge_i : range) {
136 const int2 edge = edges[edge_i];
137 r_offsets[edge_i] = vert_to_edge_offsets[edge[0]].size() - 1 +
138 vert_to_edge_offsets[edge[1]].size() - 1;
142 r_indices.reinitialize(offsets.total_size());
145 for (const int edge_i : range) {
146 const int2 edge = edges[edge_i];
147 MutableSpan<int> neighbors = r_indices.as_mutable_span().slice(offsets[edge_i]);
149 for (const Span<int> neighbor_edges : {vert_to_edge[edge[0]], vert_to_edge[edge[1]]}) {
150 for (const int neighbor_edge : neighbor_edges) {
151 if (neighbor_edge != edge_i) {
152 neighbors[count] = neighbor_edge;
169 const GroupedSpan<int> edge_to_face_map = bke::mesh::build_edge_to_face_map(
170 faces, corner_edges, edges_num, edge_to_face_offset_data, edge_to_face_indices);
174 threading::parallel_for(faces.index_range(), 4096, [&](
const IndexRange range) {
175 for (const int face_i : range) {
176 for (const int edge : corner_edges.slice(faces[face_i])) {
178 r_offsets[face_i] += edge_to_face_offsets[edge].size() - 1;
182 const OffsetIndices<int> offsets = offset_indices::accumulate_counts_to_offsets(r_offsets);
183 r_indices.reinitialize(offsets.total_size());
185 threading::parallel_for(faces.index_range(), 1024, [&](
IndexRange range) {
186 for (const int face_i : range) {
187 MutableSpan<int> neighbors = r_indices.as_mutable_span().slice(offsets[face_i]);
188 if (neighbors.is_empty()) {
192 for (const int edge : corner_edges.slice(faces[face_i])) {
193 for (const int neighbor : edge_to_face_map[edge]) {
194 if (neighbor != face_i) {
195 neighbors[count] = neighbor;
205 const AttrDomain domain,
210 case AttrDomain::Point:
213 case AttrDomain::Edge:
216 case AttrDomain::Face:
218 mesh.faces(), mesh.corner_edges(), mesh.edges_num, r_offsets, r_indices);
230 const int iterations,
243 for (const int64_t index : range) {
244 const Span<int> neighbors = neighbors_map[index];
245 const float neighbor_weight = neighbor_weights[index];
246 mixer.set(index, src[index], 1.0f);
247 for (const int neighbor : neighbors) {
248 mixer.mix_in(index, src[neighbor], neighbor_weight);
251 mixer.finalize(range);
261 using T =
typename decltype(type_tag)::type;
262 if constexpr (!std::is_same_v<T, void>) {
272 const AttrDomain domain,
273 const int iterations,
281 mesh, domain, neighbor_offsets, neighbor_indices);
285 using T = decltype(dummy);
286 result_buffer = blur_on_mesh_exec<T>(
287 neighbor_weights, neighbors_map, iterations, buffer_a.typed<T>(), buffer_b.typed<T>());
289 return result_buffer;
295 const int iterations,
302 const OffsetIndices points_by_curve = curves.points_by_curve();
305 for ([[maybe_unused]]
const int iteration :
IndexRange(iterations)) {
308 threading::parallel_for(curves.curves_range(), 256, [&](
const IndexRange range) {
309 for (const int curve_i : range) {
310 const IndexRange points = points_by_curve[curve_i];
311 if (points.size() == 1) {
313 const int point_i = points[0];
314 mixer.set(point_i, src[point_i], 1.0f);
318 for (const int point_i : points.drop_front(1).drop_back(1)) {
319 const float neighbor_weight = neighbor_weights[point_i];
320 mixer.set(point_i, src[point_i], 1.0f);
321 mixer.mix_in(point_i, src[point_i - 1], neighbor_weight);
322 mixer.mix_in(point_i, src[point_i + 1], neighbor_weight);
324 const int first_i = points[0];
325 const float first_neighbor_weight = neighbor_weights[first_i];
326 const int last_i = points.last();
327 const float last_neighbor_weight = neighbor_weights[last_i];
330 mixer.set(first_i, src[first_i], 1.0f);
331 mixer.mix_in(first_i, src[first_i + 1], first_neighbor_weight);
333 mixer.set(last_i, src[last_i], 1.0f);
334 mixer.mix_in(last_i, src[last_i - 1], last_neighbor_weight);
336 if (cyclic[curve_i]) {
338 mixer.mix_in(first_i, src[last_i], first_neighbor_weight);
340 mixer.mix_in(last_i, src[first_i], last_neighbor_weight);
343 mixer.finalize(points_by_curve[range]);
351 const int iterations,
358 using T = decltype(dummy);
359 result_buffer = blur_on_curve_exec<T>(
360 curves, neighbor_weights, iterations, buffer_a.typed<T>(), buffer_b.typed<T>());
362 return result_buffer;
368 const GField value_field_;
369 const int iterations_;
373 : bke::GeometryFieldInput(value_field.cpp_type(),
"Blur Attribute"),
374 weight_field_(std::move(weight_field)),
375 value_field_(std::move(value_field)),
376 iterations_(iterations)
383 const int64_t domain_size = context.attributes()->domain_size(context.domain());
385 GArray<> buffer_a(*type_, domain_size);
390 evaluator.
add(weight_field_);
394 if (domain_size <= 1) {
395 return GVArray::ForGArray(std::move(buffer_a));
398 if (iterations_ <= 0) {
399 return GVArray::ForGArray(std::move(buffer_a));
403 GArray<> buffer_b(*type_, domain_size);
406 switch (context.type()) {
407 case GeometryComponent::Type::Mesh:
408 if (
ELEM(context.domain(), AttrDomain::Point, AttrDomain::Edge, AttrDomain::Face)) {
409 if (
const Mesh *mesh = context.mesh()) {
411 *mesh, context.domain(), iterations_, neighbor_weights, buffer_a, buffer_b);
415 case GeometryComponent::Type::Curve:
416 case GeometryComponent::Type::GreasePencil:
417 if (context.domain() == AttrDomain::Point) {
420 *curves, iterations_, neighbor_weights, buffer_a, buffer_b);
429 if (result_buffer.
data() == buffer_a.
data()) {
430 return GVArray::ForGArray(std::move(buffer_a));
432 return GVArray::ForGArray(std::move(buffer_b));
451 return weight_field_ == other_blur->weight_field_ &&
452 value_field_ == other_blur->value_field_ && iterations_ == other_blur->iterations_;
459 const std::optional<AttrDomain> domain = bke::try_detect_field_domain(component, value_field_);
460 if (domain.has_value() && *domain == AttrDomain::Corner) {
461 return AttrDomain::Point;
469 const int iterations =
params.extract_input<
int>(
"Iterations");
473 GField output_field{std::make_shared<BlurAttributeFieldInput>(
474 std::move(weight_field), std::move(value_field), iterations)};
475 params.set_output<
GField>(
"Value", std::move(output_field));
Low-level operations for curves.
Low-level operations for grease pencil.
#define NODE_CLASS_ATTRIBUTE
#define BLI_assert_unreachable()
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
MutableSpan< T > as_mutable_span()
GMutableSpan as_mutable_span()
const void * data() const
const CPPType & type() const
const void * data() const
constexpr IndexRange index_range() const
int add(GField field, GVArray *varray_ptr)
int add_with_destination(GField field, GVMutableArray dst)
const GVArray & get_evaluated(const int field_index) const
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
const FieldNode & node() const
Vector< SocketDeclaration * > inputs
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
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
typename DefaultMixerStruct< T >::type DefaultMixer
int edge_other_vert(const int2 edge, const int vert)
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)
std::optional< eCustomDataType > socket_type_to_custom_data_type(eNodeSocketDatatype type)
static void node_geo_exec(GeoNodeExecParams params)
static Span< T > blur_on_curve_exec(const bke::CurvesGeometry &curves, const Span< float > neighbor_weights, const int iterations, const MutableSpan< T > buffer_a, const MutableSpan< T > buffer_b)
static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
static void build_vert_to_vert_by_edge_map(const Span< int2 > edges, const int verts_num, Array< int > &r_offsets, Array< int > &r_indices)
static void to_static_type_for_blur(const CPPType &type, const Func &func)
static void node_rna(StructRNA *srna)
static GSpan blur_on_mesh(const Mesh &mesh, const AttrDomain domain, const int iterations, const Span< float > neighbor_weights, const GMutableSpan buffer_a, const GMutableSpan buffer_b)
static void node_register()
static GSpan blur_on_curves(const bke::CurvesGeometry &curves, const int iterations, const Span< float > neighbor_weights, const GMutableSpan buffer_a, const GMutableSpan buffer_b)
static GroupedSpan< int > create_mesh_map(const Mesh &mesh, const AttrDomain domain, Array< int > &r_offsets, Array< int > &r_indices)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void build_face_to_face_by_edge_map(const OffsetIndices< int > faces, const Span< int > corner_edges, const int edges_num, Array< int > &r_offsets, Array< int > &r_indices)
static void build_edge_to_edge_by_vert_map(const Span< int2 > edges, const int verts_num, Array< int > &r_offsets, Array< int > &r_indices)
static void node_init(bNodeTree *, bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
static Span< T > blur_on_mesh_exec(const Span< float > neighbor_weights, const GroupedSpan< int > neighbors_map, const int iterations, const MutableSpan< T > buffer_a, const MutableSpan< T > buffer_b)
void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, Span< SocketDeclaration * > declarations)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
uint64_t get_default_hash(const T &v)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
const EnumPropertyItem rna_enum_attribute_type_items[]
unsigned __int64 uint64_t
blender::nodes::NodeDeclaration * static_declaration
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
NodeDeclareFunction declare