Blender V4.3
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
6#include "BKE_volume_grid.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#ifdef WITH_OPENVDB
18# include <openvdb/tools/Interpolation.h>
19#endif
20
21#include "node_geometry_util.hh"
22
24
26 Nearest = 0,
27 TriLinear = 1,
28 TriQuadratic = 2,
29};
30
32{
33 const bNode *node = b.node_or_null();
34 if (!node) {
35 return;
36 }
37 const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
38
39 b.add_input(data_type, "Grid").hide_value();
40 b.add_input<decl::Vector>("Position").implicit_field(implicit_field_inputs::position);
41
42 b.add_output(data_type, "Value").dependent_field({1});
43}
44
45static std::optional<eNodeSocketDatatype> node_type_for_socket_type(const bNodeSocket &socket)
46{
47 switch (socket.type) {
48 case SOCK_FLOAT:
49 return SOCK_FLOAT;
50 case SOCK_BOOLEAN:
51 return SOCK_BOOLEAN;
52 case SOCK_INT:
53 return SOCK_INT;
54 case SOCK_VECTOR:
55 case SOCK_RGBA:
56 return SOCK_VECTOR;
57 default:
58 return std::nullopt;
59 }
60}
61
63{
64 if (!U.experimental.use_new_volume_nodes) {
65 return;
66 }
67 const std::optional<eNodeSocketDatatype> node_type = node_type_for_socket_type(
68 params.other_socket());
69 if (!node_type) {
70 return;
71 }
72 if (params.in_out() == SOCK_IN) {
73 params.add_item(IFACE_("Grid"), [node_type](LinkSearchOpParams &params) {
74 bNode &node = params.add_node("GeometryNodeSampleGrid");
75 node.custom1 = *node_type;
76 params.update_and_connect_available_socket(node, "Grid");
77 });
78 const eNodeSocketDatatype other_type = eNodeSocketDatatype(params.other_socket().type);
79 if (params.node_tree().typeinfo->validate_link(other_type, SOCK_VECTOR)) {
80 params.add_item(IFACE_("Position"), [](LinkSearchOpParams &params) {
81 bNode &node = params.add_node("GeometryNodeSampleGrid");
82 params.update_and_connect_available_socket(node, "Position");
83 });
84 }
85 }
86 else {
87 params.add_item(IFACE_("Value"), [node_type](LinkSearchOpParams &params) {
88 bNode &node = params.add_node("GeometryNodeSampleGrid");
89 node.custom1 = *node_type;
90 params.update_and_connect_available_socket(node, "Value");
91 });
92 }
93}
94
95static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
96{
97 uiItemR(layout, ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
98 uiItemR(layout, ptr, "interpolation_mode", UI_ITEM_NONE, "", ICON_NONE);
99}
100
101static void node_init(bNodeTree * /*tree*/, bNode *node)
102{
103 node->custom1 = SOCK_FLOAT;
104 node->custom2 = int16_t(InterpolationMode::TriLinear);
105}
106
107#ifdef WITH_OPENVDB
108
109template<typename T>
110void sample_grid(const bke::OpenvdbGridType<T> &grid,
111 const InterpolationMode interpolation,
112 const Span<float3> positions,
113 const IndexMask &mask,
114 MutableSpan<T> dst)
115{
116 using GridType = bke::OpenvdbGridType<T>;
117 using GridValueT = typename GridType::ValueType;
118 using AccessorT = typename GridType::ConstAccessor;
119 using TraitsT = typename bke::VolumeGridTraits<T>;
120 AccessorT accessor = grid.getConstAccessor();
121
122 auto sample_data = [&](auto sampler) {
123 mask.foreach_index([&](const int64_t i) {
124 const float3 &pos = positions[i];
125 GridValueT value = sampler.wsSample(openvdb::Vec3R(pos.x, pos.y, pos.z));
126 dst[i] = TraitsT::to_blender(value);
127 });
128 };
129
130 /* Use to the Nearest Neighbor sampler for Bool grids (no interpolation). */
131 InterpolationMode real_interpolation = interpolation;
132 if constexpr (std::is_same_v<T, bool>) {
133 real_interpolation = InterpolationMode::Nearest;
134 }
135 switch (real_interpolation) {
137 openvdb::tools::GridSampler<AccessorT, openvdb::tools::BoxSampler> sampler(accessor,
138 grid.transform());
139 sample_data(sampler);
140 break;
141 }
143 openvdb::tools::GridSampler<AccessorT, openvdb::tools::QuadraticSampler> sampler(
144 accessor, grid.transform());
145 sample_data(sampler);
146 break;
147 }
149 openvdb::tools::GridSampler<AccessorT, openvdb::tools::PointSampler> sampler(
150 accessor, grid.transform());
151 sample_data(sampler);
152 break;
153 }
154 }
155}
156
157template<typename Fn> void convert_to_static_type(const VolumeGridType type, const Fn &fn)
158{
159 switch (type) {
161 fn(bool());
162 break;
164 fn(float());
165 break;
166 case VOLUME_GRID_INT:
167 fn(int());
168 break;
169 case VOLUME_GRID_MASK:
170 fn(bool());
171 break;
173 fn(float3());
174 break;
175 default:
176 break;
177 }
178}
179
180class SampleGridFunction : public mf::MultiFunction {
181 bke::GVolumeGrid grid_;
182 InterpolationMode interpolation_;
183 mf::Signature signature_;
184
185 public:
186 SampleGridFunction(bke::GVolumeGrid grid, InterpolationMode interpolation)
187 : grid_(std::move(grid)), interpolation_(interpolation)
188 {
189 BLI_assert(grid_);
190
191 const std::optional<eNodeSocketDatatype> data_type = bke::grid_type_to_socket_type(
192 grid_->grid_type());
193 const CPPType *cpp_type = bke::socket_type_to_geo_nodes_base_cpp_type(*data_type);
194 mf::SignatureBuilder builder{"Sample Grid", signature_};
195 builder.single_input<float3>("Position");
196 builder.single_output("Value", *cpp_type);
197 this->set_signature(&signature_);
198 }
199
200 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
201 {
202 const VArraySpan<float3> positions = params.readonly_single_input<float3>(0, "Position");
203 GMutableSpan dst = params.uninitialized_single_output(1, "Value");
204
205 bke::VolumeTreeAccessToken tree_token;
206 convert_to_static_type(grid_->grid_type(), [&](auto dummy) {
207 using T = decltype(dummy);
208 sample_grid<T>(
209 grid_.typed<T>().grid(tree_token), interpolation_, positions, mask, dst.typed<T>());
210 });
211 }
212};
213
214#endif /* WITH_OPENVDB */
215
217{
218#ifdef WITH_OPENVDB
219 const bNode &node = params.node();
220 const eNodeSocketDatatype data_type = eNodeSocketDatatype(node.custom1);
221 const InterpolationMode interpolation = InterpolationMode(node.custom2);
222
223 bke::GVolumeGrid grid = params.extract_input<bke::GVolumeGrid>("Grid");
224 if (!grid) {
225 params.set_default_remaining_outputs();
226 return;
227 }
228
229 auto fn = std::make_shared<SampleGridFunction>(std::move(grid), interpolation);
230 auto op = FieldOperation::Create(std::move(fn),
231 {params.extract_input<Field<float3>>("Position")});
232
234 const CPPType &output_type = *bke::socket_type_to_geo_nodes_base_cpp_type(data_type);
235 const GField output_field = conversions.try_convert(fn::GField(std::move(op)), output_type);
236 params.set_output("Value", std::move(output_field));
237
238#else
240#endif
241}
242
244 PointerRNA * /*ptr*/,
245 PropertyRNA * /*prop*/,
246 bool *r_free)
247{
248 *r_free = true;
249 return enum_items_filter(
252 });
253}
254
255static void node_rna(StructRNA *srna)
256{
258 "data_type",
259 "Data Type",
260 "Node socket data type",
265
266 static const EnumPropertyItem interpolation_mode_items[] = {
267 {int(InterpolationMode::Nearest), "NEAREST", 0, "Nearest Neighbor", ""},
268 {int(InterpolationMode::TriLinear), "TRILINEAR", 0, "Trilinear", ""},
269 {int(InterpolationMode::TriQuadratic), "TRIQUADRATIC", 0, "Triquadratic", ""},
270 {0, nullptr, 0, nullptr, nullptr},
271 };
272
274 "interpolation_mode",
275 "Interpolation Mode",
276 "How to interpolate the values between neighboring voxels",
277 interpolation_mode_items,
280}
281
282static void node_register()
283{
284 static blender::bke::bNodeType ntype;
285
286 geo_node_type_base(&ntype, GEO_NODE_SAMPLE_GRID, "Sample Grid", NODE_CLASS_CONVERTER);
287 ntype.initfunc = node_init;
288 ntype.declare = node_declare;
294
295 node_rna(ntype.rna_ext.srna);
296}
298
299} // namespace blender::nodes::node_geo_sample_grid_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
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:50
#define ELEM(...)
#define IFACE_(msgid)
@ 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
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
unsigned int U
Definition btGjkEpa3.h:78
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
local_group_size(16, 16) .push_constant(Type local_group_size(16, 16) .push_constant(Type input_tx sampler(1, ImageType::FLOAT_2D, "matte_tx") .image(0
local_group_size(16, 16) .push_constant(Type b
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
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
const DataTypeConversions & get_implicit_type_conversions()
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:4438
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
void position(const bNode &, void *r_value)
static std::optional< eNodeSocketDatatype > node_type_for_socket_type(const bNodeSocket &socket)
static void node_geo_exec(GeoNodeExecParams params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static const EnumPropertyItem * data_type_filter_fn(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
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)
void node_geo_exec_with_missing_openvdb(GeoNodeExecParams &params)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
signed short int16_t
Definition stdint.h:76
__int64 int64_t
Definition stdint.h:89
StructRNA * srna
Definition RNA_types.hh:780
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