Geometry Nodes: Add OpenVDB grid operators
Adds four new grid operator nodes that wrap OpenVDB's differential operators. All nodes take a grid input and output a grid, potentially with a different data type. New nodes: - Grid Curl: Calculate curl of vector field (Vec3 → Vec3) - Grid Divergence: Calculate divergence of vector field (Vec3 → Float) - Grid Gradient: Calculate gradient of scalar field (Float → Vec3) - Grid Laplacian: Calculate Laplacian of scalar field (Float → Float) These operators enable vector calculus operations on volume grids for effects like flow analysis, vortex detection, etc. Co-authored-by: Hans Goudey <hans@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/146845
This commit is contained in:
committed by
Hans Goudey
parent
fdfbb3ad20
commit
0a77a57c4e
@@ -935,6 +935,10 @@ class NODE_MT_gn_volume_sample_base(node_add_menu.NodeMenu):
|
||||
layout = self.layout
|
||||
self.node_operator(layout, "GeometryNodeSampleGrid")
|
||||
self.node_operator(layout, "GeometryNodeSampleGridIndex")
|
||||
self.node_operator(layout, "GeometryNodeGridCurl")
|
||||
self.node_operator(layout, "GeometryNodeGridDivergence")
|
||||
self.node_operator(layout, "GeometryNodeGridGradient")
|
||||
self.node_operator(layout, "GeometryNodeGridLaplacian")
|
||||
|
||||
self.draw_assets_for_catalog(layout, self.menu_path)
|
||||
|
||||
|
||||
@@ -10165,7 +10165,11 @@ static void rna_def_nodes(BlenderRNA *brna)
|
||||
define("GeometryNode", "GeometryNodeGizmoLinear");
|
||||
define("GeometryNode", "GeometryNodeGizmoTransform", rna_def_geo_gizmo_transform);
|
||||
define("GeometryNode", "GeometryNodeGreasePencilToCurves");
|
||||
define("GeometryNode", "GeometryNodeGridCurl");
|
||||
define("GeometryNode", "GeometryNodeGridDivergence");
|
||||
define("GeometryNode", "GeometryNodeGridGradient");
|
||||
define("GeometryNode", "GeometryNodeGridInfo");
|
||||
define("GeometryNode", "GeometryNodeGridLaplacian");
|
||||
define("GeometryNode", "GeometryNodeGridToMesh");
|
||||
define("GeometryNode", "GeometryNodeImageInfo");
|
||||
define("GeometryNode", "GeometryNodeImageTexture", def_geo_image_texture);
|
||||
|
||||
@@ -96,7 +96,11 @@ set(SRC
|
||||
nodes/node_geo_gizmo_linear.cc
|
||||
nodes/node_geo_gizmo_transform.cc
|
||||
nodes/node_geo_grease_pencil_to_curves.cc
|
||||
nodes/node_geo_grid_curl.cc
|
||||
nodes/node_geo_grid_divergence.cc
|
||||
nodes/node_geo_grid_gradient.cc
|
||||
nodes/node_geo_grid_info.cc
|
||||
nodes/node_geo_grid_laplacian.cc
|
||||
nodes/node_geo_grid_to_mesh.cc
|
||||
nodes/node_geo_image.cc
|
||||
nodes/node_geo_image_info.cc
|
||||
|
||||
51
source/blender/nodes/geometry/nodes/node_geo_grid_curl.cc
Normal file
51
source/blender/nodes/geometry/nodes/node_geo_grid_curl.cc
Normal file
@@ -0,0 +1,51 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "openvdb/tools/GridOperators.h"
|
||||
|
||||
namespace blender::nodes::node_geo_grid_curl_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Vector>("Grid").hide_value().structure_type(StructureType::Grid);
|
||||
b.add_output<decl::Vector>("Curl").structure_type(StructureType::Grid);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const bke::VolumeGrid<float3> grid = params.extract_input<bke::VolumeGrid<float3>>("Grid");
|
||||
if (!grid) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
bke::VolumeTreeAccessToken tree_token;
|
||||
const openvdb::Vec3SGrid &vdb_grid = grid.grid(tree_token);
|
||||
openvdb::Vec3SGrid::Ptr curl_vdb_grid = openvdb::tools::curl(vdb_grid);
|
||||
params.set_output("Curl", bke::VolumeGrid<float3>(std::move(curl_vdb_grid)));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static blender::bke::bNodeType ntype;
|
||||
geo_node_type_base(&ntype, "GeometryNodeGridCurl");
|
||||
ntype.ui_name = "Grid Curl";
|
||||
ntype.ui_description =
|
||||
"Calculate the magnitude and direction of circulation of a directional vector grid";
|
||||
ntype.nclass = NODE_CLASS_GEOMETRY;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.gather_link_search_ops = search_link_ops_for_volume_grid_node;
|
||||
blender::bke::node_register_type(ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_grid_curl_cc
|
||||
@@ -0,0 +1,51 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "openvdb/tools/GridOperators.h"
|
||||
|
||||
namespace blender::nodes::node_geo_grid_divergence_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Vector>("Grid").hide_value().structure_type(StructureType::Grid);
|
||||
b.add_output<decl::Float>("Divergence").structure_type(StructureType::Grid);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const bke::VolumeGrid<float3> grid = params.extract_input<bke::VolumeGrid<float3>>("Grid");
|
||||
if (!grid) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
bke::VolumeTreeAccessToken tree_token;
|
||||
const openvdb::Vec3SGrid &vdb_grid = grid.grid(tree_token);
|
||||
openvdb::FloatGrid::Ptr divergence_vdb_grid = openvdb::tools::divergence(vdb_grid);
|
||||
params.set_output("Divergence", bke::VolumeGrid<float>(std::move(divergence_vdb_grid)));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static blender::bke::bNodeType ntype;
|
||||
geo_node_type_base(&ntype, "GeometryNodeGridDivergence");
|
||||
ntype.ui_name = "Grid Divergence";
|
||||
ntype.ui_description =
|
||||
"Calculate the flow into and out of each point of a directional vector grid";
|
||||
ntype.nclass = NODE_CLASS_GEOMETRY;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.gather_link_search_ops = search_link_ops_for_volume_grid_node;
|
||||
blender::bke::node_register_type(ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_grid_divergence_cc
|
||||
@@ -0,0 +1,51 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "openvdb/tools/GridOperators.h"
|
||||
|
||||
namespace blender::nodes::node_geo_grid_gradient_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Float>("Grid").hide_value().structure_type(StructureType::Grid);
|
||||
b.add_output<decl::Vector>("Gradient").structure_type(StructureType::Grid);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const bke::VolumeGrid<float> grid = params.extract_input<bke::VolumeGrid<float>>("Grid");
|
||||
if (!grid) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
bke::VolumeTreeAccessToken tree_token;
|
||||
const openvdb::FloatGrid &vdb_grid = grid.grid(tree_token);
|
||||
openvdb::Vec3SGrid::Ptr gradient_vdb_grid = openvdb::tools::gradient(vdb_grid);
|
||||
params.set_output("Gradient", bke::VolumeGrid<float3>(std::move(gradient_vdb_grid)));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static blender::bke::bNodeType ntype;
|
||||
geo_node_type_base(&ntype, "GeometryNodeGridGradient");
|
||||
ntype.ui_name = "Grid Gradient";
|
||||
ntype.ui_description =
|
||||
"Calculate the direction and magnitude of the change in values of a scalar grid";
|
||||
ntype.nclass = NODE_CLASS_GEOMETRY;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.gather_link_search_ops = search_link_ops_for_volume_grid_node;
|
||||
blender::bke::node_register_type(ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_grid_gradient_cc
|
||||
@@ -0,0 +1,50 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_volume_grid.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "openvdb/tools/GridOperators.h"
|
||||
|
||||
namespace blender::nodes::node_geo_grid_laplacian_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Float>("Grid").hide_value().structure_type(StructureType::Grid);
|
||||
b.add_output<decl::Float>("Laplacian").structure_type(StructureType::Grid);
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const bke::VolumeGrid<float> grid = params.extract_input<bke::VolumeGrid<float>>("Grid");
|
||||
if (!grid) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
bke::VolumeTreeAccessToken tree_token;
|
||||
const openvdb::FloatGrid &vdb_grid = grid.grid(tree_token);
|
||||
openvdb::FloatGrid::Ptr laplacian_vdb_grid = openvdb::tools::laplacian(vdb_grid);
|
||||
params.set_output("Laplacian", bke::VolumeGrid<float>(std::move(laplacian_vdb_grid)));
|
||||
#else
|
||||
node_geo_exec_with_missing_openvdb(params);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static blender::bke::bNodeType ntype;
|
||||
geo_node_type_base(&ntype, "GeometryNodeGridLaplacian");
|
||||
ntype.ui_name = "Grid Laplacian";
|
||||
ntype.ui_description = "Compute the divergence of the gradient of the input grid";
|
||||
ntype.nclass = NODE_CLASS_GEOMETRY;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.gather_link_search_ops = search_link_ops_for_volume_grid_node;
|
||||
blender::bke::node_register_type(ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_grid_laplacian_cc
|
||||
BIN
tests/files/modeling/geometry_nodes/volume/grid_operators.blend
(Stored with Git LFS)
Normal file
BIN
tests/files/modeling/geometry_nodes/volume/grid_operators.blend
(Stored with Git LFS)
Normal file
Binary file not shown.
Reference in New Issue
Block a user