Blender V5.0
node_geo_sample_grid.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "DNA_userdef_types.h"
6
8#include "BKE_volume_grid.hh"
9
10#include "NOD_rna_define.hh"
12
14#include "UI_resources.hh"
15
16#include "RNA_enum_types.hh"
17
18#ifdef WITH_OPENVDB
19# include <openvdb/tools/Interpolation.h>
20#endif
21
22#include "node_geometry_util.hh"
23
25
31
33 {int(InterpolationMode::Nearest), "NEAREST", 0, N_("Nearest Neighbor"), ""},
34 {int(InterpolationMode::TriLinear), "TRILINEAR", 0, N_("Trilinear"), ""},
35 {int(InterpolationMode::TriQuadratic), "TRIQUADRATIC", 0, N_("Triquadratic"), ""},
36 {0, nullptr, 0, nullptr, nullptr},
37};
38
40{
41 const bNode *node = b.node_or_null();
42 if (!node) {
43 return;
44 }
45 const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
46
47 b.add_input(data_type, "Grid").hide_value().structure_type(StructureType::Grid);
48 b.add_input<decl::Vector>("Position").implicit_field(NODE_DEFAULT_INPUT_POSITION_FIELD);
49 b.add_input<decl::Menu>("Interpolation")
50 .static_items(interpolation_mode_items)
52 .optional_label()
53 .description("How to interpolate the values between neighboring voxels");
54
55 b.add_output(data_type, "Value").dependent_field({1});
56}
57
58static std::optional<eNodeSocketDatatype> node_type_for_socket_type(const bNodeSocket &socket)
59{
60 switch (socket.type) {
61 case SOCK_FLOAT:
62 return SOCK_FLOAT;
63 case SOCK_BOOLEAN:
64 return SOCK_BOOLEAN;
65 case SOCK_INT:
66 return SOCK_INT;
67 case SOCK_VECTOR:
68 case SOCK_RGBA:
69 return SOCK_VECTOR;
70 default:
71 return std::nullopt;
72 }
73}
74
76{
77 const std::optional<eNodeSocketDatatype> node_type = node_type_for_socket_type(
78 params.other_socket());
79 if (!node_type) {
80 return;
81 }
82 if (params.in_out() == SOCK_IN) {
83 params.add_item(IFACE_("Grid"), [node_type](LinkSearchOpParams &params) {
84 bNode &node = params.add_node("GeometryNodeSampleGrid");
85 node.custom1 = *node_type;
86 params.update_and_connect_available_socket(node, "Grid");
87 });
88 const eNodeSocketDatatype other_type = eNodeSocketDatatype(params.other_socket().type);
89 if (params.node_tree().typeinfo->validate_link(other_type, SOCK_VECTOR)) {
90 params.add_item(IFACE_("Position"), [](LinkSearchOpParams &params) {
91 bNode &node = params.add_node("GeometryNodeSampleGrid");
92 params.update_and_connect_available_socket(node, "Position");
93 });
94 }
95 }
96 else {
97 params.add_item(IFACE_("Value"), [node_type](LinkSearchOpParams &params) {
98 bNode &node = params.add_node("GeometryNodeSampleGrid");
99 node.custom1 = *node_type;
100 params.update_and_connect_available_socket(node, "Value");
101 });
102 }
103}
104
105static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
106{
107 layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
108}
109
110#ifdef WITH_OPENVDB
111
112template<typename T>
113void sample_grid(const bke::OpenvdbGridType<T> &grid,
114 const InterpolationMode interpolation,
115 const Span<float3> positions,
116 const IndexMask &mask,
117 MutableSpan<T> dst)
118{
119 using GridType = bke::OpenvdbGridType<T>;
120 using GridValueT = typename GridType::ValueType;
121 using AccessorT = typename GridType::ConstUnsafeAccessor;
122 using TraitsT = typename bke::VolumeGridTraits<T>;
123 AccessorT accessor = grid.getConstUnsafeAccessor();
124
125 auto sample_data = [&](auto sampler_type_tag) {
126 using Sampler = typename decltype(sampler_type_tag)::type;
127 mask.foreach_index([&](const int64_t i) {
128 const float3 &pos = positions[i];
129 const openvdb::Vec3R world_pos(pos.x, pos.y, pos.z);
130 const openvdb::Vec3R index_pos = grid.transform().worldToIndex(world_pos);
131 GridValueT value;
132 Sampler::sample(accessor, index_pos, value);
133 dst[i] = TraitsT::to_blender(value);
134 });
135 };
136
137 /* Use to the Nearest Neighbor sampler for Bool grids (no interpolation). */
138 InterpolationMode real_interpolation = interpolation;
139 if constexpr (std::is_same_v<T, bool>) {
140 real_interpolation = InterpolationMode::Nearest;
141 }
142 switch (real_interpolation) {
144 sample_data(TypeTag<openvdb::tools::BoxSampler>{});
145 break;
146 }
148 sample_data(TypeTag<openvdb::tools::QuadraticSampler>{});
149 break;
150 }
152 sample_data(TypeTag<openvdb::tools::PointSampler>{});
153 break;
154 }
155 }
156}
157
158template<typename Fn> void convert_to_static_type(const VolumeGridType type, const Fn &fn)
159{
160 switch (type) {
162 fn(bool());
163 break;
165 fn(float());
166 break;
167 case VOLUME_GRID_INT:
168 fn(int());
169 break;
170 case VOLUME_GRID_MASK:
171 fn(bool());
172 break;
174 fn(float3());
175 break;
176 default:
177 break;
178 }
179}
180
181class SampleGridFunction : public mf::MultiFunction {
182 bke::GVolumeGrid grid_;
183 InterpolationMode interpolation_;
184 mf::Signature signature_;
185 VolumeGridType grid_type_;
187 bke::VolumeTreeAccessToken tree_token_;
188 const openvdb::GridBase *grid_base_ = nullptr;
189
190 public:
191 SampleGridFunction(bke::GVolumeGrid grid, InterpolationMode interpolation)
192 : grid_(std::move(grid)), interpolation_(interpolation)
193 {
194 BLI_assert(grid_);
195
196 const std::optional<eNodeSocketDatatype> data_type = bke::grid_type_to_socket_type(
197 grid_->grid_type());
198 const CPPType *cpp_type = bke::socket_type_to_geo_nodes_base_cpp_type(*data_type);
199 mf::SignatureBuilder builder{"Sample Grid", signature_};
200 builder.single_input<float3>("Position");
201 builder.single_output("Value", *cpp_type);
202 this->set_signature(&signature_);
203
204 grid_base_ = &grid_->grid(tree_token_);
205 grid_type_ = grid_->grid_type();
206 }
207
208 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
209 {
210 const VArraySpan<float3> positions = params.readonly_single_input<float3>(0, "Position");
211 GMutableSpan dst = params.uninitialized_single_output(1, "Value");
212
213 bke::VolumeTreeAccessToken tree_token;
214 convert_to_static_type(grid_type_, [&](auto dummy) {
215 using T = decltype(dummy);
216 sample_grid<T>(static_cast<const bke::OpenvdbGridType<T> &>(*grid_base_),
217 interpolation_,
218 positions,
219 mask,
220 dst.typed<T>());
221 });
222 }
223};
224
225#endif /* WITH_OPENVDB */
226
228{
229#ifdef WITH_OPENVDB
230 bke::GVolumeGrid grid = params.extract_input<bke::GVolumeGrid>("Grid");
231 if (!grid) {
232 params.set_default_remaining_outputs();
233 return;
234 }
235
236 const auto interpolation = params.get_input<InterpolationMode>("Interpolation");
237 bke::SocketValueVariant position = params.extract_input<bke::SocketValueVariant>("Position");
238
239 std::string error_message;
240 bke::SocketValueVariant output_value;
242 std::make_shared<SampleGridFunction>(std::move(grid), interpolation),
243 {&position},
244 {&output_value},
245 params.user_data(),
246 error_message))
247 {
248 params.set_default_remaining_outputs();
249 params.error_message_add(NodeWarningType::Error, std::move(error_message));
250 return;
251 }
252
253 params.set_output("Value", std::move(output_value));
254#else
256#endif
257}
258
259static void node_init(bNodeTree * /*tree*/, bNode *node)
260{
261 node->custom1 = SOCK_FLOAT;
262}
263
264static void node_rna(StructRNA *srna)
265{
267 "data_type",
268 "Data Type",
269 "Node socket data type",
274}
275
276static void node_register()
277{
278 static blender::bke::bNodeType ntype;
279
280 geo_node_type_base(&ntype, "GeometryNodeSampleGrid", GEO_NODE_SAMPLE_GRID);
281 ntype.ui_name = "Sample Grid";
282 ntype.ui_description = "Retrieve values from the specified volume grid";
283 ntype.enum_name_legacy = "SAMPLE_GRID";
285 ntype.initfunc = node_init;
286 ntype.declare = node_declare;
292
293 node_rna(ntype.rna_ext.srna);
294}
296
297} // namespace blender::nodes::node_geo_sample_grid_cc
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
#define GEO_NODE_SAMPLE_GRID
VolumeGridType
@ VOLUME_GRID_VECTOR_FLOAT
@ VOLUME_GRID_MASK
@ VOLUME_GRID_BOOLEAN
@ VOLUME_GRID_INT
@ VOLUME_GRID_FLOAT
#define BLI_assert(a)
Definition BLI_assert.h:46
#define IFACE_(msgid)
@ NODE_DEFAULT_INPUT_POSITION_FIELD
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_RGBA
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
#define UI_ITEM_NONE
long long int int64_t
uint pos
VecBase< float, 3 > float3
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define T
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
static std::optional< eNodeSocketDatatype > node_type_for_socket_type(const bNodeSocket &socket)
static const EnumPropertyItem interpolation_mode_items[]
static void node_geo_exec(GeoNodeExecParams params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *, bNode *node)
static void node_gather_link_search_ops(GatherLinkSearchOpParams &params)
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)
bool execute_multi_function_on_value_variant(const MultiFunction &fn, const std::shared_ptr< MultiFunction > &owned_fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values, GeoNodesUserData *user_data, std::string &r_error_message)
const EnumPropertyItem * grid_socket_type_items_filter_fn(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
void node_geo_exec_with_missing_openvdb(GeoNodeExecParams &params)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
StructRNA * srna
int16_t custom1
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238