Blender V5.0
node_geo_grid_prune.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_volume_grid.hh"
7
8#include "NOD_rna_define.hh"
10
11#include "RNA_enum_types.hh"
12
14#include "UI_resources.hh"
15
16#include "node_geometry_util.hh"
17
18#ifdef WITH_OPENVDB
19# include "openvdb/tools/Prune.h"
20#endif
21
23
24enum class Mode : int16_t {
27 SDF = 2,
28};
29
31{
32 b.use_custom_socket_order();
33 b.allow_any_socket_order();
34 b.add_default_layout();
35 const bNode *node = b.node_or_null();
36 if (!node) {
37 return;
38 }
39 const eNodeSocketDatatype data_type = eNodeSocketDatatype(node->custom1);
40 b.add_input(data_type, "Grid").hide_value().structure_type(StructureType::Grid);
41 b.add_output(data_type, "Grid").structure_type(StructureType::Grid).align_with_previous();
42 static EnumPropertyItem mode_items[] = {
43 {int(Mode::Inactive),
44 "INACTIVE",
45 0,
46 N_("Inactive"),
47 N_("Turn inactive voxels and tiles into inactive background tiles")},
48 {int(Mode::Threshold),
49 "THRESHOLD",
50 0,
51 N_("Threshold"),
52 N_("Turn regions where all voxels have the same value and active state (within a tolerance "
53 "threshold) into inactive background tiles")},
54 {int(Mode::SDF),
55 "SDF",
56 0,
57 N_("SDF"),
58 N_("Replace inactive tiles with inactive nodes. Faster than tolerance-based pruning, "
59 "useful for cases like narrow-band SDF grids with only inside or outside background "
60 "values.")},
61 {0, nullptr, 0, nullptr, nullptr},
62 };
63 b.add_input<decl::Menu>("Mode")
64 .static_items(mode_items)
66 .structure_type(StructureType::Single)
67 .optional_label();
68 if (data_type != SOCK_BOOLEAN) {
69 auto &threshold = b.add_input(data_type, "Threshold")
70 .structure_type(StructureType::Single)
71 .usage_by_single_menu(int(Mode::Threshold));
72 switch (data_type) {
73 case SOCK_FLOAT: {
74 auto &threshold_typed = static_cast<decl::FloatBuilder &>(threshold);
75 threshold_typed.min(0.0f).default_value(0.01f);
76 break;
77 }
78 case SOCK_VECTOR: {
79 auto &threshold_typed = static_cast<decl::VectorBuilder &>(threshold);
80 threshold_typed.min(0.0f).default_value(float3(0.01f));
81 break;
82 }
83 case SOCK_INT: {
84 auto &threshold_typed = static_cast<decl::IntBuilder &>(threshold);
85 threshold_typed.min(0).default_value(0);
86 break;
87 }
88 default:
90 }
91 }
92}
93
94static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
95{
96 layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
97}
98
99static std::optional<eNodeSocketDatatype> node_type_for_socket_type(const bNodeSocket &socket)
100{
101 switch (socket.type) {
102 case SOCK_FLOAT:
103 return SOCK_FLOAT;
104 case SOCK_BOOLEAN:
105 return SOCK_BOOLEAN;
106 case SOCK_INT:
107 return SOCK_INT;
108 case SOCK_VECTOR:
109 case SOCK_RGBA:
110 return SOCK_VECTOR;
111 default:
112 return std::nullopt;
113 }
114}
115
117{
118 const std::optional<eNodeSocketDatatype> data_type = node_type_for_socket_type(
119 params.other_socket());
120 if (!data_type) {
121 return;
122 }
123 params.add_item(IFACE_("Grid"), [data_type](LinkSearchOpParams &params) {
124 bNode &node = params.add_node("GeometryNodeGridPrune");
125 node.custom1 = *data_type;
126 params.update_and_connect_available_socket(node, "Grid");
127 });
128}
129
131{
132#ifdef WITH_OPENVDB
133 bke::GVolumeGrid grid = params.extract_input<bke::GVolumeGrid>("Grid");
134 if (!grid) {
135 params.set_default_remaining_outputs();
136 return;
137 }
138 bke::VolumeTreeAccessToken tree_token;
139 openvdb::GridBase &grid_base = grid.get_for_write().grid_for_write(tree_token);
140 switch (params.extract_input<Mode>("Mode")) {
141 case Mode::Inactive: {
142 bke::volume_grid::prune_inactive(grid_base);
143 break;
144 }
145 case Mode::Threshold: {
146 const VolumeGridType grid_type = bke::volume_grid::get_type(grid_base);
147 switch (grid_type) {
148 case VOLUME_GRID_BOOLEAN: {
149 auto &grid = static_cast<openvdb::BoolGrid &>(grid_base);
150 openvdb::tools::prune(grid.tree());
151 break;
152 }
153 case VOLUME_GRID_MASK: {
154 auto &grid = static_cast<openvdb::MaskGrid &>(grid_base);
155 openvdb::tools::prune(grid.tree());
156 break;
157 }
158 case VOLUME_GRID_FLOAT: {
159 auto &grid = static_cast<openvdb::FloatGrid &>(grid_base);
160 const float threshold = params.extract_input<float>("Threshold");
161 openvdb::tools::prune(grid.tree(), threshold);
162 break;
163 }
164 case VOLUME_GRID_INT: {
165 auto &grid = static_cast<openvdb::Int32Grid &>(grid_base);
166 const int threshold = params.extract_input<int>("Threshold");
167 openvdb::tools::prune(grid.tree(), threshold);
168 break;
169 }
171 auto &grid = static_cast<openvdb::Vec3fGrid &>(grid_base);
172 const float3 threshold = params.extract_input<float3>("Threshold");
173 openvdb::tools::prune(grid.tree(),
174 openvdb::Vec3s(threshold.x, threshold.y, threshold.z));
175 break;
176 }
182 case VOLUME_GRID_POINTS: {
183 params.error_message_add(NodeWarningType::Error, "Unsupported grid type");
184 break;
185 }
186 }
187 break;
188 }
189 case Mode::SDF: {
190 const VolumeGridType grid_type = bke::volume_grid::get_type(grid_base);
191 BKE_volume_grid_type_to_static_type(grid_type, [&](auto type_tag) {
192 using GridT = typename decltype(type_tag)::type;
193 if constexpr (bke::volume_grid::is_supported_grid_type<GridT>) {
194 if constexpr (std::is_scalar_v<typename GridT::ValueType>) {
195 GridT &grid = static_cast<GridT &>(grid_base);
196 openvdb::tools::pruneLevelSet(grid.tree());
197 }
198 }
199 else {
201 }
202 });
203 break;
204 }
205 }
206 params.set_output("Grid", std::move(grid));
207#else
209#endif
210}
211
212static void node_init(bNodeTree * /*tree*/, bNode *node)
213{
214 node->custom1 = SOCK_FLOAT;
215}
216
217static void node_rna(StructRNA *srna)
218{
220 "data_type",
221 "Data Type",
222 "Node socket data type",
227}
228
229static void node_register()
230{
231 static blender::bke::bNodeType ntype;
232 geo_node_type_base(&ntype, "GeometryNodeGridPrune");
233 ntype.ui_name = "Prune Grid";
234 ntype.ui_description =
235 "Make the storage of a volume grid more efficient by collapsing data into tiles or inner "
236 "nodes";
238 ntype.declare = node_declare;
240 ntype.initfunc = node_init;
244 node_rna(ntype.rna_ext.srna);
245}
247
248} // namespace blender::nodes::node_geo_grid_prune_cc
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
VolumeGridType
@ VOLUME_GRID_VECTOR_FLOAT
@ VOLUME_GRID_MASK
@ VOLUME_GRID_VECTOR_DOUBLE
@ VOLUME_GRID_VECTOR_INT
@ VOLUME_GRID_UNKNOWN
@ VOLUME_GRID_DOUBLE
@ VOLUME_GRID_BOOLEAN
@ VOLUME_GRID_INT
@ VOLUME_GRID_INT64
@ VOLUME_GRID_POINTS
@ VOLUME_GRID_FLOAT
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define IFACE_(msgid)
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
VectorBuilder & default_value(const float2 value)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
VolumeGridType get_type(const VolumeGridData &grid)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
static std::optional< eNodeSocketDatatype > node_type_for_socket_type(const bNodeSocket &socket)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_declare(NodeDeclarationBuilder &b)
static void node_gather_link_search_ops(GatherLinkSearchOpParams &params)
static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *, bNode *node)
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)
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
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)
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238