Blender V4.3
node_geo_sample_nearest_surface.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_bvhutils.hh"
6#include "BKE_mesh.hh"
7#include "BKE_mesh_sample.hh"
8
9#include "NOD_rna_define.hh"
11
12#include "UI_interface.hh"
13#include "UI_resources.hh"
14
15#include "RNA_enum_types.hh"
16
17#include "BLI_task.hh"
18
19#include "node_geometry_util.hh"
20
22
24
26{
27 const bNode *node = b.node_or_null();
28
29 b.add_input<decl::Geometry>("Mesh").supported_type(GeometryComponent::Type::Mesh);
30 if (node != nullptr) {
31 const eCustomDataType data_type = eCustomDataType(node->custom1);
32 b.add_input(data_type, "Value").hide_value().field_on_all();
33 }
34 b.add_input<decl::Int>("Group ID")
35 .hide_value()
36 .field_on_all()
38 "Splits the faces of the input mesh into groups which can be sampled individually");
39 b.add_input<decl::Vector>("Sample Position").implicit_field(implicit_field_inputs::position);
40 b.add_input<decl::Int>("Sample Group ID").hide_value().supports_field();
41
42 if (node != nullptr) {
43 const eCustomDataType data_type = eCustomDataType(node->custom1);
44 b.add_output(data_type, "Value").dependent_field({3, 4});
45 }
46 b.add_output<decl::Bool>("Is Valid")
47 .dependent_field({3, 4})
48 .description(
49 "Whether the sampling was successful. It can fail when the sampled group is empty");
50}
51
52static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
53{
54 uiItemR(layout, ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
55}
56
57static void node_init(bNodeTree * /*tree*/, bNode *node)
58{
59 node->custom1 = CD_PROP_FLOAT;
60}
61
63{
64 const NodeDeclaration &declaration = *params.node_type().static_declaration;
66
67 const std::optional<eCustomDataType> type = bke::socket_type_to_custom_data_type(
68 eNodeSocketDatatype(params.other_socket().type));
69 if (type && *type != CD_PROP_STRING) {
70 /* The input and output sockets have the same name. */
71 params.add_item(IFACE_("Value"), [type](LinkSearchOpParams &params) {
72 bNode &node = params.add_node("GeometryNodeSampleNearestSurface");
73 node.custom1 = *type;
74 params.update_and_connect_available_socket(node, "Value");
75 });
76 }
77}
78
80 private:
81 GeometrySet source_;
82 Array<BVHTreeFromMesh> bvh_trees_;
83 VectorSet<int> group_indices_;
84
85 public:
86 SampleNearestSurfaceFunction(GeometrySet geometry, const Field<int> &group_id_field)
87 : source_(std::move(geometry))
88 {
90 static const mf::Signature signature = []() {
92 mf::SignatureBuilder builder{"Sample Nearest Surface", signature};
93 builder.single_input<float3>("Position");
94 builder.single_input<int>("Sample ID");
95 builder.single_output<int>("Triangle Index");
96 builder.single_output<float3>("Sample Position");
97 builder.single_output<bool>("Is Valid", mf::ParamFlag::SupportsUnusedOutput);
98 return signature;
99 }();
100 this->set_signature(&signature);
101
102 const Mesh &mesh = *source_.get_mesh();
103
104 /* Compute group ids on mesh. */
106 FieldEvaluator field_evaluator{field_context, mesh.faces_num};
107 field_evaluator.add(group_id_field);
108 field_evaluator.evaluate();
109 const VArray<int> group_ids = field_evaluator.get_evaluated<int>(0);
110
111 /* Compute index masks for groups. */
112 IndexMaskMemory memory;
114 group_ids, memory, group_indices_);
115 const int groups_num = group_masks.size();
116
117 /* Construct BVH tree for each group. */
118 bvh_trees_.reinitialize(groups_num);
120 IndexRange(groups_num),
121 512,
122 [&](const IndexRange range) {
123 for (const int group_i : range) {
124 const IndexMask &group_mask = group_masks[group_i];
125 BVHTreeFromMesh &bvh = bvh_trees_[group_i];
126 BKE_bvhtree_from_mesh_tris_init(mesh, group_mask, bvh);
127 }
128 },
130 [&](const int group_i) { return group_masks[group_i].size(); }, mesh.faces_num));
131 }
132
134 {
135 for (BVHTreeFromMesh &tree : bvh_trees_) {
137 }
138 }
139
140 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
141 {
142 const VArray<float3> &positions = params.readonly_single_input<float3>(0, "Position");
143 const VArray<int> &sample_ids = params.readonly_single_input<int>(1, "Sample ID");
144 MutableSpan<int> triangle_index = params.uninitialized_single_output<int>(2, "Triangle Index");
145 MutableSpan<float3> sample_position = params.uninitialized_single_output<float3>(
146 3, "Sample Position");
147 MutableSpan<bool> is_valid_span = params.uninitialized_single_output_if_required<bool>(
148 4, "Is Valid");
149
150 mask.foreach_index([&](const int i) {
151 const float3 position = positions[i];
152 const int sample_id = sample_ids[i];
153 const int group_index = group_indices_.index_of_try(sample_id);
154 if (group_index == -1) {
155 triangle_index[i] = -1;
156 sample_position[i] = float3(0, 0, 0);
157 if (!is_valid_span.is_empty()) {
158 is_valid_span[i] = false;
159 }
160 return;
161 }
162 const BVHTreeFromMesh &bvh = bvh_trees_[group_index];
163 BVHTreeNearest nearest;
164 nearest.dist_sq = FLT_MAX;
165 nearest.index = -1;
167 bvh.tree, position, &nearest, bvh.nearest_callback, const_cast<BVHTreeFromMesh *>(&bvh));
168 triangle_index[i] = nearest.index;
169 sample_position[i] = nearest.co;
170 if (!is_valid_span.is_empty()) {
171 is_valid_span[i] = true;
172 }
173 });
174 }
175
177 {
178 ExecutionHints hints;
179 hints.min_grain_size = 512;
180 return hints;
181 }
182};
183
185{
186 GeometrySet geometry = params.extract_input<GeometrySet>("Mesh");
187 const Mesh *mesh = geometry.get_mesh();
188 if (mesh == nullptr) {
189 params.set_default_remaining_outputs();
190 return;
191 }
192 if (mesh->verts_num == 0) {
193 params.set_default_remaining_outputs();
194 return;
195 }
196 if (mesh->faces_num == 0) {
197 params.error_message_add(NodeWarningType::Error, TIP_("The source mesh must have faces"));
198 params.set_default_remaining_outputs();
199 return;
200 }
201
202 auto nearest_op = FieldOperation::Create(
203 std::make_shared<SampleNearestSurfaceFunction>(geometry,
204 params.extract_input<Field<int>>("Group ID")),
205 {params.extract_input<Field<float3>>("Sample Position"),
206 params.extract_input<Field<int>>("Sample Group ID")});
207 Field<int> triangle_indices(nearest_op, 0);
208 Field<float3> nearest_positions(nearest_op, 1);
209 Field<bool> is_valid(nearest_op, 2);
210
212 std::make_shared<bke::mesh_surface_sample::BaryWeightFromPositionFn>(geometry),
213 {nearest_positions, triangle_indices}));
214
215 GField field = params.extract_input<GField>("Value");
216 auto sample_op = FieldOperation::Create(
217 std::make_shared<bke::mesh_surface_sample::BaryWeightSampleFn>(geometry, std::move(field)),
218 {triangle_indices, bary_weights});
219
220 params.set_output("Value", GField(sample_op));
221 params.set_output("Is Valid", is_valid);
222}
223
224static void node_rna(StructRNA *srna)
225{
227 "data_type",
228 "Data Type",
229 "",
234}
235
236static void node_register()
237{
238 static blender::bke::bNodeType ntype;
239
241 &ntype, GEO_NODE_SAMPLE_NEAREST_SURFACE, "Sample Nearest Surface", NODE_CLASS_GEOMETRY);
242 ntype.initfunc = node_init;
243 ntype.declare = node_declare;
249
250 node_rna(ntype.rna_ext.srna);
251}
253
254} // namespace blender::nodes::node_geo_sample_nearest_surface_cc
void free_bvhtree_from_mesh(BVHTreeFromMesh *data)
Definition bvhutils.cc:1160
void BKE_bvhtree_from_mesh_tris_init(const Mesh &mesh, const blender::IndexMask &faces_mask, BVHTreeFromMesh &r_data)
Definition bvhutils.cc:1033
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:418
int BLI_bvhtree_find_nearest(const BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
#define TIP_(msgid)
#define IFACE_(msgid)
@ CD_PROP_FLOAT
@ CD_PROP_STRING
eNodeSocketDatatype
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
#define UI_ITEM_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
int64_t index_of_try(const Key &key) const
int64_t size() const
int add(GField field, GVArray *varray_ptr)
Definition field.cc:756
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
void set_signature(const Signature *signature)
static Vector< IndexMask, 4 > from_group_ids(const VArray< int > &group_ids, IndexMaskMemory &memory, VectorSet< int > &r_index_by_group_id)
Vector< SocketDeclaration * > inputs
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
local_group_size(16, 16) .push_constant(Type b
KDTree_3d * tree
IndexRange range
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_type_size_preset(bNodeType *ntype, eNodeSizePreset size)
Definition node.cc:4614
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
std::optional< eCustomDataType > socket_type_to_custom_data_type(eNodeSocketDatatype type)
Definition node.cc:4379
const EnumPropertyItem * attribute_type_type_with_socket_fn(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
void position(const bNode &, void *r_value)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
void search_link_ops_for_declarations(GatherLinkSearchOpParams &params, 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)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
auto individual_task_sizes(Fn &&fn, const std::optional< int64_t > full_size=std::nullopt)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
const EnumPropertyItem rna_enum_attribute_type_items[]
#define FLT_MAX
Definition stdcycles.h:14
BVHTree_NearestPointCallback nearest_callback
StructRNA * srna
Definition RNA_types.hh:780
const Mesh * get_mesh() const
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126