19# include "openvdb/tools/VolumeAdvect.h"
43 N_(
"Semi-Lagrangian"),
44 N_(
"1st order semi-Lagrangian integration. Fast but least accurate, suitable for simple "
50 N_(
"2nd order midpoint integration. Good balance between speed and accuracy for most cases")},
55 N_(
"3rd order Runge-Kutta integration. Higher accuracy at moderate computational cost")},
60 N_(
"4th order Runge-Kutta integration. Highest accuracy single-step method but slower")},
65 N_(
"MacCormack scheme with implicit diffusion control. Reduces numerical dissipation while "
66 "maintaining stability")},
71 N_(
"Back and Forth Error Compensation and Correction. Advanced scheme that minimizes "
72 "dissipation and diffusion")},
73 {0,
nullptr, 0,
nullptr,
nullptr},
81 N_(
"No limiting applied. Fastest but may produce artifacts in high-order schemes")},
86 N_(
"Clamp values to the range of the original neighborhood. Prevents overshooting and "
92 N_(
"Revert to 1st order integration when clamping would be applied. More conservative than "
94 {0,
nullptr, 0,
nullptr,
nullptr},
99 b.use_custom_socket_order();
100 b.allow_any_socket_order();
101 b.add_default_layout();
103 const bNode *node =
b.node_or_null();
109 b.add_input(data_type,
"Grid")
111 .structure_type(StructureType::Grid)
112 .is_default_link_socket();
113 b.add_output(data_type,
"Grid").structure_type(StructureType::Grid).align_with_previous();
118 .description(
"Time step for advection in seconds");
123 .description(
"Numerical integration method for advection");
128 .description(
"Limiting strategy to prevent numerical artifacts");
138 switch (socket.
type) {
163 bNode &node =
params.add_node(
"GeometryNodeGridAdvect");
164 params.update_and_connect_available_socket(node,
"Velocity");
171 bNode &node =
params.add_node(
"GeometryNodeGridAdvect");
172 params.update_and_connect_available_socket(node,
"Time Step");
177 bNode &node =
params.add_node(
"GeometryNodeGridAdvect");
179 params.update_and_connect_available_socket(node,
"Grid");
184static openvdb::tools::Scheme::SemiLagrangian to_openvdb_scheme(
const IntegrationScheme scheme)
188 return openvdb::tools::Scheme::SEMI;
190 return openvdb::tools::Scheme::MID;
192 return openvdb::tools::Scheme::RK3;
194 return openvdb::tools::Scheme::RK4;
196 return openvdb::tools::Scheme::MAC;
198 return openvdb::tools::Scheme::BFECC;
200 return openvdb::tools::Scheme::SEMI;
203static openvdb::tools::Scheme::Limiter to_openvdb_limiter(
const LimiterType limiter)
207 return openvdb::tools::Scheme::NO_LIMITER;
209 return openvdb::tools::Scheme::CLAMP;
211 return openvdb::tools::Scheme::REVERT;
213 return openvdb::tools::Scheme::NO_LIMITER;
216template<
typename Gr
idType,
typename SamplerType = openvdb::tools::Sampler<1>>
217static typename GridType::Ptr advect_grid(
const GridType &grid,
218 const openvdb::Vec3SGrid &velocity_grid,
219 const float time_step,
223 openvdb::tools::VolumeAdvection<openvdb::Vec3SGrid, false> advection(velocity_grid);
225 advection.setIntegrator(to_openvdb_scheme(scheme));
226 advection.setLimiter(to_openvdb_limiter(limiter));
227 return advection.template advect<GridType, SamplerType>(grid, time_step);
234 bke::GVolumeGrid grid =
params.extract_input<bke::GVolumeGrid>(
"Grid");
236 params.set_default_remaining_outputs();
242 if (!velocity_grid) {
243 params.set_output(
"Grid", std::move(grid));
247 const float time_step =
params.extract_input<
float>(
"Time Step");
251 bke::VolumeTreeAccessToken tree_token;
252 bke::VolumeTreeAccessToken velocity_token;
253 const openvdb::GridBase &grid_base = grid->grid(tree_token);
254 const openvdb::Vec3SGrid &velocity_vdb_grid = velocity_grid.grid(velocity_token);
258 if (!grid_base.hasUniformVoxels()) {
261 TIP_(
"The input grid must have a uniform voxel scale to be advected."));
262 params.set_output(
"Grid", std::move(grid));
268 BKE_volume_grid_type_to_static_type(grid_type, [&](
auto grid_type_tag) {
269 using GridType =
typename decltype(grid_type_tag)::type;
270 if constexpr (std::is_same_v<GridType, openvdb::FloatGrid> ||
271 std::is_same_v<GridType, openvdb::Int32Grid> ||
272 std::is_same_v<GridType, openvdb::Vec3fGrid>)
274 typename GridType::Ptr
result = advect_grid(
275 static_cast<const GridType &
>(grid->grid(tree_token)),
280 params.set_output(
"Grid", bke::GVolumeGrid(std::move(
result)));
284 params.set_default_remaining_outputs();
316 "Node socket data type",
327 return node.input_by_identifier(output_socket.
identifier);
336 "Move grid values through a velocity field using numerical integration. Supports multiple "
337 "integration schemes for different accuracy and performance trade-offs";
#define NODE_CLASS_GEOMETRY
static double Clamp(const double x, const double min, const double max)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
StructureType structure_type
void node_register_type(bNodeType &ntype)
static void node_rna(StructRNA *srna)
static const bNodeSocket * node_internally_linked_input(const bNodeTree &, const bNode &node, const bNodeSocket &output_socket)
static const EnumPropertyItem * advect_grid_socket_type_filter(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
static const EnumPropertyItem integration_scheme_items[]
static void node_register()
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static std::optional< eNodeSocketDatatype > node_type_for_socket_type(const bNodeSocket &socket)
static void node_init(bNodeTree *, bNode *node)
static const EnumPropertyItem limiter_type_items[]
static void node_gather_link_search_ops(GatherLinkSearchOpParams ¶ms)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
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 ¶ms)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
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[]
NodeInternallyLinkedInputFunction internally_linked_input
std::string ui_description
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
NodeDeclareFunction declare
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)