Blender  V3.3
node_geo_mesh_to_points.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 
5 #include "DNA_pointcloud_types.h"
6 
7 #include "BKE_attribute_math.hh"
8 #include "BKE_pointcloud.h"
9 
10 #include "UI_interface.h"
11 #include "UI_resources.h"
12 
13 #include "node_geometry_util.hh"
14 
15 using blender::Array;
16 
18 
20 
22 {
23  b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
24  b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
25  b.add_input<decl::Vector>(N_("Position")).implicit_field();
26  b.add_input<decl::Float>(N_("Radius"))
27  .default_value(0.05f)
28  .min(0.0f)
29  .subtype(PROP_DISTANCE)
30  .supports_field();
31  b.add_output<decl::Geometry>(N_("Points"));
32 }
33 
34 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
35 {
36  uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
37 }
38 
40 {
41  NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__);
43  node->storage = data;
44 }
45 
47  const IndexMask mask,
48  GMutableSpan dst)
49 {
50  BLI_assert(src.type() == dst.type());
51  BLI_assert(mask.size() == dst.size());
52  threading::parallel_for(mask.index_range(), 4096, [&](IndexRange range) {
53  src.materialize_compressed_to_uninitialized(mask.slice(range), dst.slice(range).data());
54  });
55 }
56 
57 static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
58  Field<float3> &position_field,
59  Field<float> &radius_field,
60  Field<bool> &selection_field,
61  const eAttrDomain domain)
62 {
63  const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
64  if (mesh_component == nullptr) {
65  geometry_set.remove_geometry_during_modify();
66  return;
67  }
68  GeometryComponentFieldContext field_context{*mesh_component, domain};
69  const int domain_num = mesh_component->attribute_domain_size(domain);
70  if (domain_num == 0) {
71  geometry_set.remove_geometry_during_modify();
72  return;
73  }
74  fn::FieldEvaluator evaluator{field_context, domain_num};
75  evaluator.set_selection(selection_field);
76  /* Evaluating directly into the point cloud doesn't work because we are not using the full
77  * "min_array_size" array but compressing the selected elements into the final array with no
78  * gaps. */
79  evaluator.add(position_field);
80  evaluator.add(radius_field);
81  evaluator.evaluate();
82  const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
83 
84  PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
85  geometry_set.replace_pointcloud(pointcloud);
87  *pointcloud);
88 
89  GSpanAttributeWriter position = pointcloud_attributes.lookup_or_add_for_write_only_span(
90  "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
92  evaluator.get_evaluated(0), selection, position.span);
93  position.finish();
94 
95  GSpanAttributeWriter radius = pointcloud_attributes.lookup_or_add_for_write_only_span(
96  "radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
98  evaluator.get_evaluated(1), selection, radius.span);
99  radius.finish();
100 
104  attributes.remove("position");
105 
106  for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
107  const AttributeIDRef attribute_id = entry.key;
108  const eCustomDataType data_type = entry.value.data_type;
109  GVArray src = mesh_component->attributes()->lookup_or_default(attribute_id, domain, data_type);
110  GSpanAttributeWriter dst = pointcloud_attributes.lookup_or_add_for_write_only_span(
111  attribute_id, ATTR_DOMAIN_POINT, data_type);
112  if (dst && src) {
114  dst.finish();
115  }
116  }
117 
119 }
120 
122 {
123  GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
124  Field<float3> position = params.extract_input<Field<float3>>("Position");
125  Field<float> radius = params.extract_input<Field<float>>("Radius");
126  Field<bool> selection = params.extract_input<Field<bool>>("Selection");
127 
128  /* Use another multi-function operation to make sure the input radius is greater than zero.
129  * TODO: Use mutable multi-function once that is supported. */
130  static fn::CustomMF_SI_SO<float, float> max_zero_fn(
131  __func__,
132  [](float value) { return std::max(0.0f, value); },
134  auto max_zero_op = std::make_shared<FieldOperation>(
135  FieldOperation(max_zero_fn, {std::move(radius)}));
136  Field<float> positive_radius(std::move(max_zero_op), 0);
137 
138  const NodeGeometryMeshToPoints &storage = node_storage(params.node());
140 
141  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
142  switch (mode) {
145  geometry_set, position, positive_radius, selection, ATTR_DOMAIN_POINT);
146  break;
149  geometry_set, position, positive_radius, selection, ATTR_DOMAIN_EDGE);
150  break;
153  geometry_set, position, positive_radius, selection, ATTR_DOMAIN_FACE);
154  break;
157  geometry_set, position, positive_radius, selection, ATTR_DOMAIN_CORNER);
158  break;
159  }
160  });
161 
162  params.set_output("Points", std::move(geometry_set));
163 }
164 
165 } // namespace blender::nodes::node_geo_mesh_to_points_cc
166 
168 {
169  namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc;
170 
171  static bNodeType ntype;
172 
179  &ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage);
180  nodeRegisterType(&ntype);
181 }
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:29
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:28
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
#define GEO_NODE_MESH_TO_POINTS
Definition: BKE_node.h:1435
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
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))
Definition: node.cc:4426
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
General operations for point clouds.
struct PointCloud * BKE_pointcloud_new_nomain(int totpoint)
Definition: pointcloud.cc:243
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
eCustomDataType
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
GeometryNodeMeshToPointsMode
@ GEO_NODE_MESH_TO_POINTS_FACES
@ GEO_NODE_MESH_TO_POINTS_VERTICES
@ GEO_NODE_MESH_TO_POINTS_CORNERS
@ GEO_NODE_MESH_TO_POINTS_EDGES
@ PROP_DISTANCE
Definition: RNA_types.h:149
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
int attribute_domain_size(eAttrDomain domain) const
Definition: geometry_set.cc:63
std::optional< blender::bke::AttributeAccessor > attributes() const final
const CPPType & type() const
int64_t size() const
bool remove(const Key &key)
Definition: BLI_map.hh:323
ItemIterator items() const
Definition: BLI_map.hh:859
OperationNode * node
SyclQueue void void * src
void * tree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud)
MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
static void geometry_set_mesh_to_points(GeometrySet &geometry_set, Field< float3 > &position_field, Field< float > &radius_field, Field< bool > &selection_field, const eAttrDomain domain)
static void materialize_compressed_to_uninitialized_threaded(const GVArray &src, const IndexMask mask, GMutableSpan dst)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_mesh_to_points()
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)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
void keep_only_during_modify(const blender::Span< GeometryComponentType > component_types)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) 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
void modify_geometry_sets(ForeachSubGeometryCallback callback)
void remove_geometry_during_modify()
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
float max
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480