Blender V4.5
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
13#include "UI_interface.hh"
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{
34 const bNode *node = b.node_or_null();
35 if (!node) {
36 return;
37 }
38 const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
39
40 b.add_input(data_type, "Grid").hide_value().structure_type(StructureType::Grid);
41 b.add_input<decl::Vector>("Position").implicit_field(NODE_DEFAULT_INPUT_POSITION_FIELD);
42
43 b.add_output(data_type, "Value").dependent_field({1});
44}
45
46static std::optional<eNodeSocketDatatype> node_type_for_socket_type(const bNodeSocket &socket)
47{
48 switch (socket.type) {
49 case SOCK_FLOAT:
50 return SOCK_FLOAT;
51 case SOCK_BOOLEAN:
52 return SOCK_BOOLEAN;
53 case SOCK_INT:
54 return SOCK_INT;
55 case SOCK_VECTOR:
56 case SOCK_RGBA:
57 return SOCK_VECTOR;
58 default:
59 return std::nullopt;
60 }
61}
62
64{
65 if (!USER_EXPERIMENTAL_TEST(&U, use_new_volume_nodes)) {
66 return;
67 }
68 const std::optional<eNodeSocketDatatype> node_type = node_type_for_socket_type(
69 params.other_socket());
70 if (!node_type) {
71 return;
72 }
73 if (params.in_out() == SOCK_IN) {
74 params.add_item(IFACE_("Grid"), [node_type](LinkSearchOpParams &params) {
75 bNode &node = params.add_node("GeometryNodeSampleGrid");
76 node.custom1 = *node_type;
77 params.update_and_connect_available_socket(node, "Grid");
78 });
79 const eNodeSocketDatatype other_type = eNodeSocketDatatype(params.other_socket().type);
80 if (params.node_tree().typeinfo->validate_link(other_type, SOCK_VECTOR)) {
81 params.add_item(IFACE_("Position"), [](LinkSearchOpParams &params) {
82 bNode &node = params.add_node("GeometryNodeSampleGrid");
83 params.update_and_connect_available_socket(node, "Position");
84 });
85 }
86 }
87 else {
88 params.add_item(IFACE_("Value"), [node_type](LinkSearchOpParams &params) {
89 bNode &node = params.add_node("GeometryNodeSampleGrid");
90 node.custom1 = *node_type;
91 params.update_and_connect_available_socket(node, "Value");
92 });
93 }
94}
95
96static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
97{
98 layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
99 layout->prop(ptr, "interpolation_mode", UI_ITEM_NONE, "", ICON_NONE);
100}
101
102static void node_init(bNodeTree * /*tree*/, bNode *node)
103{
104 node->custom1 = SOCK_FLOAT;
105 node->custom2 = int16_t(InterpolationMode::TriLinear);
106}
107
108#ifdef WITH_OPENVDB
109
110template<typename T>
111void sample_grid(const bke::OpenvdbGridType<T> &grid,
112 const InterpolationMode interpolation,
113 const Span<float3> positions,
114 const IndexMask &mask,
115 MutableSpan<T> dst)
116{
117 using GridType = bke::OpenvdbGridType<T>;
118 using GridValueT = typename GridType::ValueType;
119 using AccessorT = typename GridType::ConstAccessor;
120 using TraitsT = typename bke::VolumeGridTraits<T>;
121 AccessorT accessor = grid.getConstAccessor();
122
123 auto sample_data = [&](auto sampler) {
124 mask.foreach_index([&](const int64_t i) {
125 const float3 &pos = positions[i];
126 GridValueT value = sampler.wsSample(openvdb::Vec3R(pos.x, pos.y, pos.z));
127 dst[i] = TraitsT::to_blender(value);
128 });
129 };
130
131 /* Use to the Nearest Neighbor sampler for Bool grids (no interpolation). */
132 InterpolationMode real_interpolation = interpolation;
133 if constexpr (std::is_same_v<T, bool>) {
134 real_interpolation = InterpolationMode::Nearest;
135 }
136 switch (real_interpolation) {
138 openvdb::tools::GridSampler<AccessorT, openvdb::tools::BoxSampler> sampler(accessor,
139 grid.transform());
140 sample_data(sampler);
141 break;
142 }
144 openvdb::tools::GridSampler<AccessorT, openvdb::tools::QuadraticSampler> sampler(
145 accessor, grid.transform());
146 sample_data(sampler);
147 break;
148 }
150 openvdb::tools::GridSampler<AccessorT, openvdb::tools::PointSampler> sampler(
151 accessor, grid.transform());
152 sample_data(sampler);
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
186 public:
187 SampleGridFunction(bke::GVolumeGrid grid, InterpolationMode interpolation)
188 : grid_(std::move(grid)), interpolation_(interpolation)
189 {
190 BLI_assert(grid_);
191
192 const std::optional<eNodeSocketDatatype> data_type = bke::grid_type_to_socket_type(
193 grid_->grid_type());
194 const CPPType *cpp_type = bke::socket_type_to_geo_nodes_base_cpp_type(*data_type);
195 mf::SignatureBuilder builder{"Sample Grid", signature_};
196 builder.single_input<float3>("Position");
197 builder.single_output("Value", *cpp_type);
198 this->set_signature(&signature_);
199 }
200
201 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
202 {
203 const VArraySpan<float3> positions = params.readonly_single_input<float3>(0, "Position");
204 GMutableSpan dst = params.uninitialized_single_output(1, "Value");
205
206 bke::VolumeTreeAccessToken tree_token;
207 convert_to_static_type(grid_->grid_type(), [&](auto dummy) {
208 using T = decltype(dummy);
209 sample_grid<T>(
210 grid_.typed<T>().grid(tree_token), interpolation_, positions, mask, dst.typed<T>());
211 });
212 }
213};
214
215#endif /* WITH_OPENVDB */
216
218{
219#ifdef WITH_OPENVDB
220 const bNode &node = params.node();
221 const eNodeSocketDatatype data_type = eNodeSocketDatatype(node.custom1);
222 const InterpolationMode interpolation = InterpolationMode(node.custom2);
223
224 bke::GVolumeGrid grid = params.extract_input<bke::GVolumeGrid>("Grid");
225 if (!grid) {
226 params.set_default_remaining_outputs();
227 return;
228 }
229
230 auto fn = std::make_shared<SampleGridFunction>(std::move(grid), interpolation);
231 auto op = FieldOperation::Create(std::move(fn),
232 {params.extract_input<Field<float3>>("Position")});
233
235 const CPPType &output_type = *bke::socket_type_to_geo_nodes_base_cpp_type(data_type);
236 const GField output_field = conversions.try_convert(fn::GField(std::move(op)), output_type);
237 params.set_output("Value", std::move(output_field));
238
239#else
241#endif
242}
243
245 PointerRNA * /*ptr*/,
246 PropertyRNA * /*prop*/,
247 bool *r_free)
248{
249 *r_free = true;
250 return enum_items_filter(
253 });
254}
255
256static void node_rna(StructRNA *srna)
257{
259 "data_type",
260 "Data Type",
261 "Node socket data type",
266
267 static const EnumPropertyItem interpolation_mode_items[] = {
268 {int(InterpolationMode::Nearest), "NEAREST", 0, "Nearest Neighbor", ""},
269 {int(InterpolationMode::TriLinear), "TRILINEAR", 0, "Trilinear", ""},
270 {int(InterpolationMode::TriQuadratic), "TRIQUADRATIC", 0, "Triquadratic", ""},
271 {0, nullptr, 0, nullptr, nullptr},
272 };
273
275 "interpolation_mode",
276 "Interpolation Mode",
277 "How to interpolate the values between neighboring voxels",
278 interpolation_mode_items,
281}
282
283static void node_register()
284{
285 static blender::bke::bNodeType ntype;
286
287 geo_node_type_base(&ntype, "GeometryNodeSampleGrid", GEO_NODE_SAMPLE_GRID);
288 ntype.ui_name = "Sample Grid";
289 ntype.enum_name_legacy = "SAMPLE_GRID";
291 ntype.initfunc = node_init;
292 ntype.declare = node_declare;
298
299 node_rna(ntype.rna_ext.srna);
300}
302
303} // namespace blender::nodes::node_geo_sample_grid_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:439
#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 ELEM(...)
#define IFACE_(msgid)
@ NODE_DEFAULT_INPUT_POSITION_FIELD
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_FLOAT
@ SOCK_RGBA
#define USER_EXPERIMENTAL_TEST(userdef, member)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
#define UI_ITEM_NONE
#define U
long long int int64_t
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
uint pos
VecBase< float, 3 > float3
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
const DataTypeConversions & get_implicit_type_conversions()
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:5413
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, std::string idname, const std::optional< int16_t > legacy_type)
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
StructRNA * srna
Definition RNA_types.hh:909
int16_t custom1
int16_t custom2
Defines a node type.
Definition BKE_node.hh:226
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:347
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:371
NodeDeclareFunction declare
Definition BKE_node.hh:355
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
PointerRNA * ptr
Definition wm_files.cc:4227