29 b.add_input<
decl::Bool>(
N_(
"Selection")).hide_value().default_value(
true).supports_field();
34 .description(
N_(
"The number of duplicates to create for each element"));
37 .description(
N_(
"The duplicated geometry, not including the original geometry"));
40 .
description(
N_(
"The indices of the duplicates for each element"));
52 uiItemR(layout,
ptr,
"domain", 0,
"", ICON_NONE);
68 {component_type}, component_type,
false, attributes);
75 return {offsets[index], offsets[index + 1] - offsets[index]};
85 total +=
std::max(counts[selection[i]], 0);
87 offsets.
last() = total;
101 for (const int i : range) {
102 dst.slice(range_for_offsets_index(offsets, i)).fill(src[selection[i]]);
111 for (const int i : range) {
112 dst[i] = src[mapping[i]];
119 for (
const int i :
src.index_range()) {
130 for (const int i : range) {
131 dst[offsets[i]] = src[i];
132 const int count = offsets[i + 1] - offsets[i];
136 for (const int i_duplicate : IndexRange(1, count - 1)) {
137 dst[offsets[i] + i_duplicate] = noise::hash(src[i], i_duplicate);
155 for (
const int i :
indices.index_range()) {
159 duplicate_indices.
finish();
171 if (!src_attribute) {
176 if (!dst_attribute) {
195 geometry_set, component_type);
200 if (!src_attribute || src_attribute.
domain != domain) {
207 attribute_id, out_domain, data_type);
208 if (!dst_attribute) {
212 using T = decltype(dummy);
215 threaded_slice_fill<T>(offsets, selection,
src, dst);
243 if (!src_attribute) {
252 attribute_id, out_domain, data_type);
253 if (!dst_attribute) {
258 using T = decltype(dummy);
262 switch (out_domain) {
264 threaded_slice_fill<T>(curve_offsets, selection,
src, dst);
268 for (const int i_selection : range) {
269 const int i_src_curve = selection[i_selection];
270 const Span<T> curve_src = src.slice(src_curves.points_for_curve(i_src_curve));
271 for (const int i_dst_curve : range_for_offsets_index(curve_offsets, i_selection)) {
272 dst.slice(dst_curves.points_for_curve(i_dst_curve)).copy_from(curve_src);
281 dst_attribute.finish();
297 if (!src_attribute) {
303 if (!dst_attribute) {
311 for (const int i_selection : range) {
312 const int i_src_curve = selection[i_selection];
313 const Span<int> curve_src = src.slice(src_curves.points_for_curve(i_src_curve));
314 const IndexRange duplicates_range = range_for_offsets_index(curve_offsets, i_selection);
315 for (const int i_duplicate : IndexRange(duplicates_range.size()).drop_front(1)) {
316 const int i_dst_curve = duplicates_range[i_duplicate];
318 curve_src, i_duplicate, dst.slice(dst_curves.points_for_curve(i_dst_curve)));
322 dst_attribute.finish();
343 evaluator.add(count_field);
344 evaluator.set_selection(selection_field);
345 evaluator.evaluate();
346 const VArray<int> counts = evaluator.get_evaluated<
int>(0);
347 const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
350 Array<int> curve_offsets(selection.size() + 1);
351 Array<int> point_offsets(selection.size() + 1);
353 int dst_curves_num = 0;
354 int dst_points_num = 0;
355 for (
const int i_curve : selection.index_range()) {
357 curve_offsets[i_curve] = dst_curves_num;
358 point_offsets[i_curve] = dst_points_num;
359 dst_curves_num +=
count;
360 dst_points_num +=
count *
curves.points_for_curve(selection[i_curve]).size();
362 curve_offsets.
last() = dst_curves_num;
363 point_offsets.
last() = dst_points_num;
371 for (const int i_selection : range) {
372 const int i_src_curve = selection[i_selection];
373 const IndexRange src_curve_range = curves.points_for_curve(i_src_curve);
374 const IndexRange dst_curves_range = range_for_offsets_index(curve_offsets, i_selection);
375 MutableSpan<int> dst_offsets = all_dst_offsets.slice(dst_curves_range);
376 for (const int i_duplicate : IndexRange(dst_curves_range.size())) {
377 dst_offsets[i_duplicate] = point_offsets[i_selection] +
378 src_curve_range.size() * i_duplicate;
382 all_dst_offsets.last() = dst_points_num;
388 if (attribute_outputs.duplicate_index) {
396 geometry_set.replace_curves(new_curves_id);
424 if (!src_attribute) {
432 attribute_id, out_domain, data_type);
433 if (!dst_attribute) {
438 using T = decltype(dummy);
442 switch (out_domain) {
444 threaded_slice_fill<T>(offsets, selection,
src, dst);
447 threaded_mapped_copy<T>(edge_mapping,
src, dst);
450 threaded_mapped_copy<T>(vert_mapping,
src, dst);
453 threaded_mapped_copy<T>(loop_mapping,
src, dst);
478 if (!src_attribute) {
483 if (!dst_attribute) {
494 if (range.
size() == 0) {
497 const MPoly &source = polys[i_poly];
498 for ([[maybe_unused]]
const int i_duplicate :
IndexRange(range.
size())) {
500 if (i_duplicate == 0) {
501 dst[loop_index] =
src[vert_mapping[loop_index]];
504 dst[loop_index] =
noise::hash(
src[vert_mapping[loop_index]], i_duplicate);
534 evaluator.
add(count_field);
543 for (
const int i_selection : selection.
index_range()) {
544 const int count =
std::max(counts[selection[i_selection]], 0);
545 offsets[i_selection] = total_polys;
546 total_polys +=
count;
547 total_loops +=
count * polys[selection[i_selection]].totloop;
549 offsets[selection.
size()] = total_polys;
563 for (
const int i_selection : selection.
index_range()) {
566 const MPoly &source = polys[selection[i_selection]];
567 for ([[maybe_unused]]
const int i_duplicate :
IndexRange(poly_range.
size())) {
572 loop_mapping[loop_index] = source.
loopstart + i_loops;
573 new_verts[loop_index] =
verts[current_loop.
v];
574 vert_mapping[loop_index] = current_loop.
v;
575 new_edges[loop_index] = edges[current_loop.
e];
576 edge_mapping[loop_index] = current_loop.
e;
577 new_edges[loop_index].v1 = loop_index;
578 if (i_loops + 1 != source.
totloop) {
579 new_edges[loop_index].v2 = loop_index + 1;
584 new_loops[loop_index].v = loop_index;
585 new_loops[loop_index].e = loop_index;
642 if (!src_attribute) {
650 attribute_id, out_domain, data_type);
651 if (!dst_attribute) {
655 using T = decltype(dummy);
659 switch (out_domain) {
661 threaded_slice_fill<T>(offsets, selection,
src, dst);
664 threaded_mapped_copy<T>(point_mapping,
src, dst);
685 if (!src_attribute) {
690 if (!dst_attribute) {
699 for (const int i_selection : range) {
700 const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
701 if (edge_range.size() == 0) {
704 const MEdge &edge = edges[selection[i_selection]];
705 const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
707 dst[vert_range[0]] = src[edge.v1];
708 dst[vert_range[1]] = src[edge.v2];
709 for (const int i_duplicate : IndexRange(1, edge_range.size() - 1)) {
710 dst[vert_range[i_duplicate * 2]] = noise::hash(src[edge.v1], i_duplicate);
711 dst[vert_range[i_duplicate * 2 + 1]] = noise::hash(src[edge.v2], i_duplicate);
715 dst_attribute.finish();
734 evaluator.add(count_field);
735 evaluator.set_selection(selection_field);
736 evaluator.evaluate();
737 const VArray<int> counts = evaluator.get_evaluated<
int>(0);
738 const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
748 for (const int i_selection : range) {
749 const MEdge &edge = edges[selection[i_selection]];
750 const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
751 const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
753 for (const int i_duplicate : IndexRange(edge_range.size())) {
754 vert_orig_indices[vert_range[i_duplicate * 2]] = edge.v1;
755 vert_orig_indices[vert_range[i_duplicate * 2 + 1]] = edge.v2;
761 for (const int i_selection : range) {
762 const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
763 const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
764 for (const int i_duplicate : IndexRange(edge_range.size())) {
765 MEdge &new_edge = new_edges[edge_range[i_duplicate]];
766 new_edge.v1 = vert_range[i_duplicate * 2];
767 new_edge.v2 = vert_range[i_duplicate * 2] + 1;
768 new_edge.flag = ME_LOOSEEDGE;
786 if (attribute_outputs.duplicate_index) {
794 geometry_set.replace_mesh(new_mesh);
817 evaluator.add(count_field);
818 evaluator.set_selection(selection_field);
819 evaluator.evaluate();
820 const VArray<int> counts = evaluator.get_evaluated<
int>(0);
821 const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
824 const int dst_num = offsets.
last();
828 for (const int i_curve : range) {
829 const IndexRange points = src_curves.points_for_curve(i_curve);
830 point_to_curve_map.as_mutable_span().slice(points).fill(i_curve);
839 new_curve_offsets[i] = i;
841 new_curve_offsets.
last() = dst_num;
847 const AttributeIDRef attribute_id = entry.key;
848 GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
849 if (!src_attribute) {
855 src_attribute.varray.type());
856 GSpanAttributeWriter dst_attribute =
858 attribute_id, domain, data_type);
859 if (!dst_attribute) {
864 using T = decltype(dummy);
865 VArraySpan<T>
src{src_attribute.varray.typed<
T>()};
866 MutableSpan<T> dst = dst_attribute.span.typed<
T>();
871 for (const int i_selection : range) {
872 const T &src_value = src[point_to_curve_map[selection[i_selection]]];
873 const IndexRange duplicate_range = range_for_offsets_index(offsets, i_selection);
874 dst.slice(duplicate_range).fill(src_value);
885 dst_attribute.finish();
890 if (attribute_outputs.duplicate_index) {
898 geometry_set.replace_curves(new_curves_id);
918 evaluator.add(count_field);
919 evaluator.set_selection(selection_field);
920 evaluator.evaluate();
921 const VArray<int> counts = evaluator.get_evaluated<
int>(0);
922 const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
970 evaluator.
add(count_field);
971 evaluator.set_selection(selection_field);
972 evaluator.evaluate();
973 const VArray<int> counts = evaluator.get_evaluated<
int>(0);
974 const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
1014 switch (component_type) {
1018 geometry_set, count_field, selection_field, attribute_outputs);
1051 geometry_set.
clear();
1060 evaluator.add(count_field);
1061 evaluator.set_selection(selection_field);
1062 evaluator.evaluate();
1063 IndexMask selection = evaluator.get_evaluated_selection_as_mask();
1064 const VArray<int> counts = evaluator.get_evaluated<
int>(0);
1067 if (offsets.last() == 0) {
1068 geometry_set.
clear();
1074 dst_instances.
resize(offsets.last());
1075 for (
const int i_selection : selection.
index_range()) {
1077 if (range.
size() == 0) {
1082 const int new_handle = dst_instances.
add_reference(reference);
1104 geometry_set = std::move(dst_geometry);
1123 if (
params.output_is_required(
"Duplicate Index")) {
1132 switch (duplicate_domain) {
1134 duplicate_curves(geometry_set, count_field, selection_field, attribute_outputs);
1137 duplicate_faces(geometry_set, count_field, selection_field, attribute_outputs);
1140 duplicate_edges(geometry_set, count_field, selection_field, attribute_outputs);
1143 duplicate_points(geometry_set, count_field, selection_field, attribute_outputs);
1153 params.set_default_remaining_outputs();
1157 if (attribute_outputs.duplicate_index) {
1160 AnonymousAttributeFieldInput::Create<int>(std::move(attribute_outputs.duplicate_index),
1161 params.attribute_producer_name()));
1163 params.set_output(
"Geometry", std::move(geometry_set));
1178 "NodeGeometryDuplicateElements",
Low-level operations for curves.
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ GEO_COMPONENT_TYPE_CURVE
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
#define NODE_CLASS_GEOMETRY
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
#define GEO_NODE_DUPLICATE_ELEMENTS
void nodeRegisterType(struct bNodeType *ntype)
General operations for point clouds.
struct PointCloud * BKE_pointcloud_new_nomain(int totpoint)
#define BLI_assert_unreachable()
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
const Curves * get_for_read() const
static void remember_deformed_curve_positions_if_necessary(GeometrySet &geometry)
int attribute_domain_size(eAttrDomain domain) const
blender::Span< int > instance_reference_handles() const
std::optional< blender::bke::AttributeAccessor > attributes() const final
std::optional< blender::bke::MutableAttributeAccessor > attributes_for_write() final
int add_reference(const InstanceReference &reference)
blender::Span< InstanceReference > references() const
void resize(int capacity)
blender::MutableSpan< blender::float4x4 > instance_transforms()
int instances_num() const
const Mesh * get_for_read() const
std::optional< blender::bke::AttributeAccessor > attributes() const final
const T & last(const int64_t n=0) const
Span< T > as_span() const
MutableSpan< T > typed() const
const CPPType & type() const
VArray< T > typed() const
IndexRange index_range() const
constexpr int64_t size() const
bool remove(const Key &key)
ItemIterator items() const
constexpr int64_t size() const
constexpr T & last(const int64_t n=0) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & last(const int64_t n=0) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
void append(const T &value)
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
IndexMask get_evaluated_selection_as_mask()
void set_selection(Field< bool > selection)
int add(GField field, GVArray *varray_ptr)
const GVArray & get_evaluated(const int field_index) const
StringRefNull description() const
SyclQueue void void * src
ccl_gpu_kernel_postfix int ccl_global int * indices
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
void curves_copy_parameters(const Curves &src, Curves &dst)
MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
AttributeAccessor mesh_attributes(const Mesh &mesh)
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
Curves * curves_new_nomain(int points_num, int curves_num)
OwnedAnonymousAttributeID< true > StrongAnonymousAttributeID
static Array< int > accumulate_counts_to_offsets(const IndexMask selection, const VArray< int > &counts)
NODE_STORAGE_FUNCS(NodeGeometryDuplicateElements)
static void duplicate_edges(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void threaded_mapped_copy(const Span< int > mapping, const Span< T > src, MutableSpan< T > dst)
static void duplicate_points(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void copy_stable_id_edges(const Mesh &mesh, const IndexMask selection, const Span< int > edge_offsets, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void copy_face_attributes_without_id(GeometrySet &geometry_set, const Span< int > edge_mapping, const Span< int > vert_mapping, const Span< int > loop_mapping, const Span< int > offsets, const IndexMask selection, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void threaded_slice_fill(Span< int > offsets, const IndexMask selection, Span< T > src, MutableSpan< T > dst)
static void duplicate_points_curve(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void create_duplicate_index_attribute(bke::MutableAttributeAccessor attributes, const eAttrDomain output_domain, const IndexMask selection, const IndexAttributes &attribute_outputs, const Span< int > offsets)
static Map< AttributeIDRef, AttributeKind > gather_attributes_without_id(const GeometrySet &geometry_set, const GeometryComponentType component_type)
static void copy_stable_id_point(const Span< int > offsets, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void copy_hashed_ids(const Span< int > src, const int hash, MutableSpan< int > dst)
static IndexRange range_for_offsets_index(const Span< int > offsets, const int index)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void duplicate_faces(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void threaded_id_offset_copy(const Span< int > offsets, const Span< int > src, MutableSpan< int > dst)
static void node_declare(NodeDeclarationBuilder &b)
static void copy_stable_id_faces(const Mesh &mesh, const IndexMask selection, const Span< int > poly_offsets, const Span< int > vert_mapping, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves, const IndexMask selection, const Span< int > curve_offsets, bke::CurvesGeometry &dst_curves)
static void duplicate_curves(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void duplicate_points_mesh(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void copy_edge_attributes_without_id(GeometrySet &geometry_set, const Span< int > point_mapping, const Span< int > offsets, const IndexMask selection, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void duplicate_points_pointcloud(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void node_geo_exec(GeoNodeExecParams params)
static void copy_curve_attributes_without_id(const GeometrySet &geometry_set, const bke::CurvesGeometry &src_curves, const IndexMask selection, const Span< int > curve_offsets, bke::CurvesGeometry &dst_curves)
static void duplicate_instances(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static void copy_attributes_without_id(GeometrySet &geometry_set, const GeometryComponentType component_type, const eAttrDomain domain, const Span< int > offsets, const IndexMask selection, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static MPoly new_poly(const int loopstart, const int totloop)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
void register_node_type_geo_duplicate_elements()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
void node_free_standard_storage(bNode *node)
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
void keep_only_during_modify(const blender::Span< GeometryComponentType > component_types)
blender::Vector< GeometryComponentType > gather_component_types(bool include_instances, bool ignore_empty) const
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
const Mesh * get_mesh_for_read() const
void gather_attributes_for_propagation(blender::Span< GeometryComponentType > component_types, GeometryComponentType dst_component_type, bool include_instances, blender::Map< blender::bke::AttributeIDRef, blender::bke::AttributeKind > &r_attributes) const
bool has_instances() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
void remove_geometry_during_modify()
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
bool has_pointcloud() const
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
NodeDeclareFunction declare
MutableVArraySpan< T > span
StrongAnonymousAttributeID duplicate_index