17#include "RNA_prototypes.hh"
31namespace grid =
bke::volume_grid;
35 b.use_custom_socket_order();
36 b.allow_any_socket_order();
37 b.add_default_layout();
40 const bNode *node =
b.node_or_null();
47 b.add_input(data_type,
"Topology").structure_type(StructureType::Grid);
56 b.add_input(data_type, item.
name, input_identifier)
59 b.add_output(data_type, item.
name, output_identifier)
60 .structure_type(StructureType::Grid)
61 .align_with_previous()
62 .description(
"Output grid with evaluated field values");
65 b.add_input<
decl::Extend>(
"",
"__extend__").structure_type(StructureType::Field);
67 .structure_type(StructureType::Grid)
68 .align_with_previous();
83 panel->use_property_split_set(
true);
84 panel->use_property_decorate_set(
false);
85 panel->prop(item_ptr,
"data_type",
UI_ITEM_NONE, std::nullopt, ICON_NONE);
92 switch (socket.
type) {
116 bNode &node =
params.add_node(
"GeometryNodeFieldToGrid");
117 node_storage(node).data_type = *data_type;
118 params.update_and_connect_available_socket(node,
"Topology");
121 bNode &node =
params.add_node(
"GeometryNodeFieldToGrid");
123 params.node_tree, node, *data_type,
params.socket.name);
124 params.update_and_connect_available_socket(node,
params.socket.name);
129 bNode &node =
params.add_node(
"GeometryNodeFieldToGrid");
131 params.node_tree, node, *data_type,
params.socket.name);
132 params.update_and_connect_available_socket(node,
params.socket.name);
139 const openvdb::math::Transform &
transform,
140 const grid::LeafNodeMask &leaf_node_mask,
141 const openvdb::CoordBBox &leaf_bbox,
142 const grid::GetVoxelsFn get_voxels_fn,
154 [&](
const int64_t i) {
return leaf_node_mask.isOn(
i); });
156 const openvdb::Coord any_voxel_in_leaf = leaf_bbox.min();
159 get_voxels_fn(voxels);
161 bke::VoxelFieldContext field_context{
transform, voxels};
162 fn::FieldEvaluator evaluator{field_context, &index_mask};
164 Array<MutableSpan<bool>> boolean_outputs(fields.
size());
166 const CPPType &type = fields[
i].cpp_type();
167 grid::to_typed_grid(*output_grids[
i], [&](
auto &
grid) {
168 using GridT =
typename std::decay_t<
decltype(
grid)>;
169 using ValueT =
typename GridT::ValueType;
172 auto *leaf_node =
tree.probeLeaf(any_voxel_in_leaf);
177 if constexpr (std::is_same_v<ValueT, bool>) {
179 evaluator.add_with_destination(fields[
i], boolean_outputs[
i]);
183 ValueT *buffer = leaf_node->buffer().data();
184 evaluator.add_with_destination(fields[
i],
185 GMutableSpan(type, buffer, grid::LeafNodeMask::SIZE));
190 evaluator.evaluate();
193 if (!boolean_outputs[
i].is_empty()) {
194 grid::set_mask_leaf_buffer_from_bools(
static_cast<openvdb::BoolGrid &
>(*output_grids[
i]),
202BLI_NOINLINE static void process_voxels(
const Span<fn::GField> fields,
203 const openvdb::math::Transform &
transform,
204 const Span<openvdb::Coord> voxels,
205 const Span<openvdb::GridBase::Ptr> output_grids)
208 AlignedBuffer<8192, 8> allocation_buffer;
210 scope.
allocator().provide_buffer(allocation_buffer);
212 bke::VoxelFieldContext field_context{
transform, voxels};
213 fn::FieldEvaluator evaluator{field_context, voxels_num};
215 Array<GMutableSpan> output_values(output_grids.
size());
217 const CPPType &type = fields[
i].cpp_type();
218 output_values[
i] = {type, scope.
allocator().allocate_array(type, voxels_num), voxels_num};
219 evaluator.add_with_destination(fields[
i], output_values[
i]);
221 evaluator.evaluate();
224 grid::set_grid_values(*output_grids[
i], output_values[
i], voxels);
228BLI_NOINLINE static void process_tiles(
const Span<fn::GField> fields,
229 const openvdb::math::Transform &
transform,
230 const Span<openvdb::CoordBBox>
tiles,
231 const Span<openvdb::GridBase::Ptr> output_grids)
234 AlignedBuffer<8192, 8> allocation_buffer;
236 scope.
allocator().provide_buffer(allocation_buffer);
239 fn::FieldEvaluator evaluator{field_context, tiles_num};
241 Array<GMutableSpan> output_values(output_grids.
size());
243 const CPPType &type = fields[
i].cpp_type();
244 output_values[
i] = {type, scope.
allocator().allocate_array(type, tiles_num), tiles_num};
245 evaluator.add_with_destination(fields[
i], output_values[
i]);
247 evaluator.evaluate();
250 grid::set_tile_values(*output_grids[
i], output_values[
i],
tiles);
254BLI_NOINLINE static void process_background(
const Span<fn::GField> fields,
255 const openvdb::math::Transform &
transform,
256 const Span<openvdb::GridBase::Ptr> output_grids)
258 AlignedBuffer<256, 8> allocation_buffer;
260 scope.
allocator().provide_buffer(allocation_buffer);
262 static const openvdb::CoordBBox background_space = openvdb::CoordBBox::inf();
263 bke::TilesFieldContext field_context(
transform, Span<openvdb::CoordBBox>(&background_space, 1));
264 fn::FieldEvaluator evaluator(field_context, 1);
266 Array<GMutablePointer> output_values(output_grids.
size());
268 const CPPType &type = fields[
i].cpp_type();
269 output_values[
i] = {type, scope.
allocator().allocate(type)};
270 evaluator.add_with_destination(fields[
i], GMutableSpan{type, output_values[
i].
get(), 1});
272 evaluator.evaluate();
275 grid::set_grid_background(*output_grids[
i], output_values[
i]);
285 bke::GVolumeGrid topology_grid =
params.extract_input<bke::GVolumeGrid>(
"Topology");
286 if (!topology_grid) {
288 params.set_default_remaining_outputs();
292 bke::VolumeTreeAccessToken tree_token;
293 const openvdb::GridBase &topology_base = topology_grid->grid(tree_token);
294 const openvdb::math::Transform &
transform = topology_base.transform();
305 const int item_i = required_items[
i];
310 openvdb::MaskTree mask_tree;
311 grid::to_typed_grid(topology_base,
312 [&](
const auto &grid) { mask_tree.topologyUnion(grid.tree()); });
316 const int item_i = required_items[
i];
319 output_grids[
i] = grid::create_grid_with_topology(mask_tree,
transform, grid_type);
322 grid::parallel_grid_topology_tasks(
324 [&](
const grid::LeafNodeMask &leaf_node_mask,
325 const openvdb::CoordBBox &leaf_bbox,
326 const grid::GetVoxelsFn get_voxels_fn) {
328 fields,
transform, leaf_node_mask, leaf_bbox, get_voxels_fn, output_grids);
331 process_voxels(fields,
transform, voxels, output_grids);
337 process_background(fields,
transform, output_grids);
340 const int item_i = required_items[
i];
342 params.set_output(identifier, bke::GVolumeGrid(std::move(output_grids[
i])));
367 dst_node->
storage = dst_storage;
397 return node.input_by_identifier(output_socket.
identifier);
405 ntype.
ui_name =
"Field to Grid";
407 "Create new grids by evaluating new values on an existing volume grid topology";
#define NODE_STORAGE_FUNCS(StorageT)
#define NODE_CLASS_GEOMETRY
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
BMesh const char void * data
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static const CPPType & get()
LinearAllocator & allocator()
constexpr int64_t size() const
constexpr IndexRange index_range() const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
void provide_buffer(void *buffer, const int64_t size)
MutableSpan< T > allocate_array(int64_t size)
LinearAllocator & allocator()
constexpr int64_t size() const
constexpr IndexRange index_range() const
void append(const T &value)
IndexRange index_range() const
int64_t min_array_size() const
ccl_gpu_kernel_postfix ccl_global KernelWorkTile * tiles
void * MEM_callocN(size_t len, const char *str)
void * MEM_dupallocN(const void *vmemh)
void MEM_freeN(void *vmemh)
std::optional< VolumeGridType > socket_type_to_grid_type(eNodeSocketDatatype type)
void node_register_type(bNodeType &ntype)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
static std::optional< eNodeSocketDatatype > node_type_for_socket_type(const bNodeSocket &socket)
static void node_declare(NodeDeclarationBuilder &b)
static void node_operators()
static void node_gather_link_search_ops(GatherLinkSearchOpParams ¶ms)
static bool node_insert_link(bke::NodeInsertLinkParams ¶ms)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
FieldToGridItemsAccessor ItemsAccessor
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static void node_register()
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void node_free_storage(bNode *node)
static void node_init(bNodeTree *, bNode *node)
static const bNodeSocket * node_internally_linked_input(const bNodeTree &, const bNode &node, const bNodeSocket &output_socket)
void make_common_operators()
static void draw_items_list_with_operators(const bContext *C, uiLayout *layout, const bNodeTree &tree, const bNode &node)
static void draw_active_item_props(const bNodeTree &tree, const bNode &node, const FunctionRef< void(PointerRNA *item_ptr)> draw_item)
void blend_write(BlendWriter *writer, const bNode &node)
void destruct_array(bNode &node)
void blend_read_data(BlendDataReader *reader, bNode &node)
void copy_array(const bNode &src_node, bNode &dst_node)
Accessor::ItemT * add_item_with_socket_type_and_name(bNodeTree &ntree, bNode &node, const eNodeSocketDatatype socket_type, const char *name, std::optional< int > dimensions=std::nullopt)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt, typename Accessor::ItemT **r_new_item=nullptr)
void node_geo_exec_with_missing_openvdb(GeoNodeExecParams ¶ms)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
GeometryNodeFieldToGridItem * items
NodeInternallyLinkedInputFunction internally_linked_input
NodeBlendWriteFunction blend_write_storage_content
std::string ui_description
NodeBlendDataReadFunction blend_data_read_storage_content
void(* initfunc)(bNodeTree *ntree, bNode *node)
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
bool(* insert_link)(NodeInsertLinkParams ¶ms)
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
NodeDeclareFunction declare
void(* register_operators)()
bool ignore_inferred_input_socket_visibility
static StructRNA * item_srna
static std::string input_socket_identifier_for_item(const GeometryNodeFieldToGridItem &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
GeometryNodeFieldToGridItem ItemT
static std::string output_socket_identifier_for_item(const GeometryNodeFieldToGridItem &item)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
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)