Geometry Nodes: Add Sample Volume node
This commit adds a new experimental node "Sample Volume". It's purpose is to be able to sample values from a volume grid given a position field. The 'Grid' input accepts a named attribute input with the name of the volume grid to sample. Values will be implicitly converted from the grid type to the specified value type. Pull Request: #107656
This commit is contained in:
@@ -613,6 +613,7 @@ class NODE_MT_category_GEO_VOLUME(Menu):
|
||||
layout.separator()
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeMeanFilterSDFVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeOffsetSDFVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSampleVolume")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSDFVolumeSphere")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeInputSignedDistance")
|
||||
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
|
||||
|
||||
@@ -1304,6 +1304,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define GEO_NODE_SIMULATION_INPUT 2100
|
||||
#define GEO_NODE_SIMULATION_OUTPUT 2101
|
||||
#define GEO_NODE_INPUT_SIGNED_DISTANCE 2102
|
||||
#define GEO_NODE_SAMPLE_VOLUME 2103
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
@@ -1636,6 +1636,13 @@ typedef struct NodeGeometryDistributePointsInVolume {
|
||||
uint8_t mode;
|
||||
} NodeGeometryDistributePointsInVolume;
|
||||
|
||||
typedef struct NodeGeometrySampleVolume {
|
||||
/* eCustomDataType. */
|
||||
int8_t grid_type;
|
||||
/* GeometryNodeSampleVolumeInterpolationMode */
|
||||
int8_t interpolation_mode;
|
||||
} NodeGeometrySampleVolume;
|
||||
|
||||
typedef struct NodeFunctionCompare {
|
||||
/* NodeCompareOperation */
|
||||
int8_t operation;
|
||||
@@ -2439,6 +2446,12 @@ typedef enum GeometryNodeScaleElementsMode {
|
||||
GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
|
||||
} GeometryNodeScaleElementsMode;
|
||||
|
||||
typedef enum GeometryNodeSampleVolumeInterpolationMode {
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST = 0,
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR = 1,
|
||||
GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRIQUADRATIC = 2,
|
||||
} GeometryNodeSampleVolumeInterpolationMode;
|
||||
|
||||
typedef enum NodeCombSepColorMode {
|
||||
NODE_COMBSEP_COLOR_RGB = 0,
|
||||
NODE_COMBSEP_COLOR_HSV = 1,
|
||||
|
||||
@@ -11000,6 +11000,44 @@ static void def_geo_attribute_capture(StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_geo_sample_volume(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem interpolation_mode_items[] = {
|
||||
{GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST, "NEAREST", 0, "Nearest Neighbor", ""},
|
||||
{GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR, "TRILINEAR", 0, "Trilinear", ""},
|
||||
{GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRIQUADRATIC,
|
||||
"TRIQUADRATIC",
|
||||
0,
|
||||
"Triquadratic",
|
||||
""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem grid_type_items[] = {
|
||||
{CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"},
|
||||
{CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"},
|
||||
{CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"},
|
||||
{CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometrySampleVolume", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "interpolation_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, interpolation_mode_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Interpolation Mode", "How to interpolate the values from neighboring voxels");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "grid_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, grid_type_items);
|
||||
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
|
||||
RNA_def_property_ui_text(prop, "Grid Type", "Type of grid to sample data from");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
|
||||
}
|
||||
|
||||
static void def_geo_image(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
@@ -402,6 +402,7 @@ DefNode(GeometryNode, GEO_NODE_SAMPLE_INDEX, def_geo_sample_index, "SAMPLE_INDEX
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, def_geo_sample_nearest_surface, "SAMPLE_NEAREST_SURFACE", SampleNearestSurface, "Sample Nearest Surface", "Calculate the interpolated value of a mesh attribute on the closest point of its surface")
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position. Similar to the \"Index of Nearest\" node")
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_UV_SURFACE, def_geo_sample_uv_surface, "SAMPLE_UV_SURFACE", SampleUVSurface, "Sample UV Surface", "Calculate the interpolated values of a mesh attribute at a UV coordinate")
|
||||
DefNode(GeometryNode, GEO_NODE_SAMPLE_VOLUME, def_geo_sample_volume, "SAMPLE_VOLUME", SampleVolume, "Sample Volume", "Calculate the interpolated values of a Volume grid at the specified position")
|
||||
DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "Scale groups of connected edges and faces")
|
||||
DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "Scale geometry instances in local or global space")
|
||||
DefNode(GeometryNode, GEO_NODE_SDF_VOLUME_SPHERE, 0, "SDF_VOLUME_SPHERE", SDFVolumeSphere, "SDF Volume Sphere", "Generate an SDF Volume Sphere")
|
||||
|
||||
@@ -153,6 +153,7 @@ set(SRC
|
||||
nodes/node_geo_sample_nearest.cc
|
||||
nodes/node_geo_sample_nearest_surface.cc
|
||||
nodes/node_geo_sample_uv_surface.cc
|
||||
nodes/node_geo_sample_volume.cc
|
||||
nodes/node_geo_scale_elements.cc
|
||||
nodes/node_geo_scale_instances.cc
|
||||
nodes/node_geo_sdf_volume_sphere.cc
|
||||
|
||||
@@ -137,6 +137,7 @@ void register_geometry_nodes()
|
||||
register_node_type_geo_sample_nearest_surface();
|
||||
register_node_type_geo_sample_nearest();
|
||||
register_node_type_geo_sample_uv_surface();
|
||||
register_node_type_geo_sample_volume();
|
||||
register_node_type_geo_scale_elements();
|
||||
register_node_type_geo_scale_instances();
|
||||
register_node_type_geo_sdf_volume_sphere();
|
||||
|
||||
@@ -134,6 +134,7 @@ void register_node_type_geo_sample_index();
|
||||
void register_node_type_geo_sample_nearest_surface();
|
||||
void register_node_type_geo_sample_nearest();
|
||||
void register_node_type_geo_sample_uv_surface();
|
||||
void register_node_type_geo_sample_volume();
|
||||
void register_node_type_geo_scale_elements();
|
||||
void register_node_type_geo_scale_instances();
|
||||
void register_node_type_geo_sdf_volume_sphere();
|
||||
|
||||
378
source/blender/nodes/geometry/nodes/node_geo_sample_volume.cc
Normal file
378
source/blender/nodes/geometry/nodes/node_geo_sample_volume.cc
Normal file
@@ -0,0 +1,378 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "BKE_type_conversions.hh"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "BLI_virtual_array.hh"
|
||||
|
||||
#include "NOD_add_node_search.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/openvdb.h>
|
||||
# include <openvdb/tools/Interpolation.h>
|
||||
#endif
|
||||
|
||||
namespace blender::nodes::node_geo_sample_volume_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometrySampleVolume)
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>(CTX_N_(BLT_I18NCONTEXT_ID_ID, "Volume"))
|
||||
.translation_context(BLT_I18NCONTEXT_ID_ID)
|
||||
.supported_type(GEO_COMPONENT_TYPE_VOLUME);
|
||||
|
||||
std::string grid_socket_description = N_(
|
||||
"Expects a Named Attribute with the name of a Grid in the Volume");
|
||||
|
||||
b.add_input<decl::Vector>(N_("Grid"), "Grid_Vector")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
b.add_input<decl::Float>(N_("Grid"), "Grid_Float")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
b.add_input<decl::Bool>(N_("Grid"), "Grid_Bool")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
b.add_input<decl::Int>(N_("Grid"), "Grid_Int")
|
||||
.field_on_all()
|
||||
.hide_value()
|
||||
.description(grid_socket_description);
|
||||
|
||||
b.add_input<decl::Vector>(N_("Position")).implicit_field(implicit_field_inputs::position);
|
||||
|
||||
b.add_output<decl::Vector>(N_("Value"), "Value_Vector").dependent_field({5});
|
||||
b.add_output<decl::Float>(N_("Value"), "Value_Float").dependent_field({5});
|
||||
b.add_output<decl::Bool>(N_("Value"), "Value_Bool").dependent_field({5});
|
||||
b.add_output<decl::Int>(N_("Value"), "Value_Int").dependent_field({5});
|
||||
}
|
||||
|
||||
static void search_node_add_ops(GatherAddNodeSearchParams ¶ms)
|
||||
{
|
||||
if (!U.experimental.use_new_volume_nodes) {
|
||||
return;
|
||||
}
|
||||
blender::nodes::search_node_add_ops_for_basic_node(params);
|
||||
}
|
||||
|
||||
static void search_link_ops(GatherLinkSearchOpParams ¶ms)
|
||||
{
|
||||
if (!U.experimental.use_new_volume_nodes) {
|
||||
return;
|
||||
}
|
||||
const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
|
||||
search_link_ops_for_declarations(params, declaration.inputs.as_span().take_back(1));
|
||||
search_link_ops_for_declarations(params, declaration.inputs.as_span().take_front(1));
|
||||
|
||||
const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
|
||||
(eNodeSocketDatatype)params.other_socket().type);
|
||||
if (type && *type != CD_PROP_STRING) {
|
||||
/* The input and output sockets have the same name. */
|
||||
params.add_item(IFACE_("Grid"), [type](LinkSearchOpParams ¶ms) {
|
||||
bNode &node = params.add_node("GeometryNodeSampleVolume");
|
||||
node_storage(node).grid_type = *type;
|
||||
params.update_and_connect_available_socket(node, "Grid");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetPropDecorate(layout, false);
|
||||
uiItemR(layout, ptr, "grid_type", 0, "", ICON_NONE);
|
||||
uiItemR(layout, ptr, "interpolation_mode", 0, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
NodeGeometrySampleVolume *data = MEM_cnew<NodeGeometrySampleVolume>(__func__);
|
||||
data->grid_type = CD_PROP_FLOAT;
|
||||
data->interpolation_mode = GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
const NodeGeometrySampleVolume &storage = node_storage(*node);
|
||||
const eCustomDataType grid_type = eCustomDataType(storage.grid_type);
|
||||
|
||||
bNodeSocket *socket_value_geometry = static_cast<bNodeSocket *>(node->inputs.first);
|
||||
bNodeSocket *socket_value_vector = socket_value_geometry->next;
|
||||
bNodeSocket *socket_value_float = socket_value_vector->next;
|
||||
bNodeSocket *socket_value_boolean = socket_value_float->next;
|
||||
bNodeSocket *socket_value_int32 = socket_value_boolean->next;
|
||||
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_vector, grid_type == CD_PROP_FLOAT3);
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_float, grid_type == CD_PROP_FLOAT);
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_boolean, grid_type == CD_PROP_BOOL);
|
||||
bke::nodeSetSocketAvailability(ntree, socket_value_int32, grid_type == CD_PROP_INT32);
|
||||
|
||||
bNodeSocket *out_socket_value_vector = static_cast<bNodeSocket *>(node->outputs.first);
|
||||
bNodeSocket *out_socket_value_float = out_socket_value_vector->next;
|
||||
bNodeSocket *out_socket_value_boolean = out_socket_value_float->next;
|
||||
bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next;
|
||||
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_vector, grid_type == CD_PROP_FLOAT3);
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_float, grid_type == CD_PROP_FLOAT);
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_boolean, grid_type == CD_PROP_BOOL);
|
||||
bke::nodeSetSocketAvailability(ntree, out_socket_value_int32, grid_type == CD_PROP_INT32);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
static const StringRefNull get_grid_name(GField &field)
|
||||
{
|
||||
if (const auto *attribute_field_input = dynamic_cast<const AttributeFieldInput *>(&field.node()))
|
||||
{
|
||||
return attribute_field_input->attribute_name();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static const blender::CPPType *vdb_grid_type_to_cpp_type(const VolumeGridType grid_type)
|
||||
{
|
||||
switch (grid_type) {
|
||||
case VOLUME_GRID_FLOAT:
|
||||
return &CPPType::get<float>();
|
||||
case VOLUME_GRID_VECTOR_FLOAT:
|
||||
return &CPPType::get<float3>();
|
||||
case VOLUME_GRID_INT:
|
||||
return &CPPType::get<int>();
|
||||
case VOLUME_GRID_BOOLEAN:
|
||||
return &CPPType::get<bool>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename GridT>
|
||||
void sample_grid(openvdb::GridBase::ConstPtr base_grid,
|
||||
const Span<float3> positions,
|
||||
const IndexMask mask,
|
||||
GMutableSpan dst,
|
||||
const GeometryNodeSampleVolumeInterpolationMode interpolation_mode)
|
||||
{
|
||||
using ValueT = typename GridT::ValueType;
|
||||
using AccessorT = typename GridT::ConstAccessor;
|
||||
const GridT::ConstPtr grid = openvdb::gridConstPtrCast<GridT>(base_grid);
|
||||
AccessorT accessor = grid->getConstAccessor();
|
||||
|
||||
auto sample_data = [&](auto sampler) {
|
||||
mask.foreach_index([&](const int64_t i) {
|
||||
const float3 &pos = positions[i];
|
||||
ValueT value = sampler.wsSample(openvdb::Vec3R(pos.x, pos.y, pos.z));
|
||||
|
||||
/* Special case for vector. */
|
||||
if constexpr (std::is_same_v<GridT, openvdb::VectorGrid>) {
|
||||
openvdb::Vec3f vec = static_cast<openvdb::Vec3f>(value);
|
||||
dst.typed<float3>()[i] = float3(vec.asV());
|
||||
}
|
||||
else {
|
||||
dst.typed<ValueT>()[i] = value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
switch (interpolation_mode) {
|
||||
case GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRILINEAR: {
|
||||
openvdb::tools::GridSampler<AccessorT, openvdb::tools::BoxSampler> sampler(
|
||||
accessor, grid->transform());
|
||||
sample_data(sampler);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_TRIQUADRATIC: {
|
||||
openvdb::tools::GridSampler<AccessorT, openvdb::tools::QuadraticSampler> sampler(
|
||||
accessor, grid->transform());
|
||||
sample_data(sampler);
|
||||
break;
|
||||
}
|
||||
case GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST:
|
||||
default: {
|
||||
openvdb::tools::GridSampler<AccessorT, openvdb::tools::PointSampler> sampler(
|
||||
accessor, grid->transform());
|
||||
sample_data(sampler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SampleVolumeFunction : public mf::MultiFunction {
|
||||
openvdb::GridBase::ConstPtr base_grid_;
|
||||
VolumeGridType grid_type_;
|
||||
GeometryNodeSampleVolumeInterpolationMode interpolation_mode_;
|
||||
mf::Signature signature_;
|
||||
|
||||
public:
|
||||
SampleVolumeFunction(openvdb::GridBase::ConstPtr base_grid,
|
||||
GeometryNodeSampleVolumeInterpolationMode interpolation_mode)
|
||||
: base_grid_(std::move(base_grid)), interpolation_mode_(interpolation_mode)
|
||||
{
|
||||
grid_type_ = BKE_volume_grid_type_openvdb(*base_grid_);
|
||||
const CPPType *grid_cpp_type = vdb_grid_type_to_cpp_type(grid_type_);
|
||||
BLI_assert(grid_cpp_type != nullptr);
|
||||
mf::SignatureBuilder builder{"Sample Volume", signature_};
|
||||
builder.single_input<float3>("Position");
|
||||
builder.single_output("Value", *grid_cpp_type);
|
||||
this->set_signature(&signature_);
|
||||
}
|
||||
|
||||
void call(IndexMask mask, mf::Params params, mf::Context /*context*/) const override
|
||||
{
|
||||
const VArraySpan<float3> positions = params.readonly_single_input<float3>(0, "Position");
|
||||
GMutableSpan dst = params.uninitialized_single_output(1, "Value");
|
||||
|
||||
switch (grid_type_) {
|
||||
case VOLUME_GRID_FLOAT:
|
||||
sample_grid<openvdb::FloatGrid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
case VOLUME_GRID_INT:
|
||||
sample_grid<openvdb::Int32Grid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
case VOLUME_GRID_BOOLEAN:
|
||||
sample_grid<openvdb::BoolGrid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
case VOLUME_GRID_VECTOR_FLOAT:
|
||||
sample_grid<openvdb::VectorGrid>(base_grid_, positions, mask, dst, interpolation_mode_);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static GField get_input_attribute_field(GeoNodeExecParams ¶ms, const eCustomDataType data_type)
|
||||
{
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT:
|
||||
return params.extract_input<Field<float>>("Grid_Float");
|
||||
case CD_PROP_FLOAT3:
|
||||
return params.extract_input<Field<float3>>("Grid_Vector");
|
||||
case CD_PROP_BOOL:
|
||||
return params.extract_input<Field<bool>>("Grid_Bool");
|
||||
case CD_PROP_INT32:
|
||||
return params.extract_input<Field<int>>("Grid_Int");
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static void output_attribute_field(GeoNodeExecParams ¶ms, GField field)
|
||||
{
|
||||
switch (bke::cpp_type_to_custom_data_type(field.cpp_type())) {
|
||||
case CD_PROP_FLOAT:
|
||||
params.set_output("Value_Float", Field<float>(field));
|
||||
break;
|
||||
case CD_PROP_FLOAT3:
|
||||
params.set_output("Value_Vector", Field<float3>(field));
|
||||
break;
|
||||
case CD_PROP_BOOL:
|
||||
params.set_output("Value_Bool", Field<bool>(field));
|
||||
break;
|
||||
case CD_PROP_INT32:
|
||||
params.set_output("Value_Int", Field<int>(field));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WITH_OPENVDB */
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume");
|
||||
if (!geometry_set.has_volume()) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
const NodeGeometrySampleVolume &storage = node_storage(params.node());
|
||||
const eCustomDataType output_field_type = eCustomDataType(storage.grid_type);
|
||||
auto interpolation_mode = GeometryNodeSampleVolumeInterpolationMode(storage.interpolation_mode);
|
||||
|
||||
GField grid_field = get_input_attribute_field(params, output_field_type);
|
||||
const StringRefNull grid_name = get_grid_name(grid_field);
|
||||
if (grid_name == "") {
|
||||
params.error_message_add(NodeWarningType::Error, TIP_("Grid name needs to be specified"));
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
|
||||
const VolumeComponent *component = geometry_set.get_component_for_read<VolumeComponent>();
|
||||
const Volume *volume = component->get_for_read();
|
||||
BKE_volume_load(volume, DEG_get_bmain(params.depsgraph()));
|
||||
const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
|
||||
if (volume_grid == nullptr) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
openvdb::GridBase::ConstPtr base_grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
|
||||
const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*base_grid);
|
||||
|
||||
/* Check that the grid type is supported. */
|
||||
const CPPType *grid_cpp_type = vdb_grid_type_to_cpp_type(grid_type);
|
||||
if (grid_cpp_type == nullptr) {
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error, TIP_("The grid type is unsupported"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use to the Nearest Neighbor sampler for Bool grids (no interpolation). */
|
||||
if (grid_type == VOLUME_GRID_BOOLEAN &&
|
||||
interpolation_mode != GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST)
|
||||
{
|
||||
interpolation_mode = GEO_NODE_SAMPLE_VOLUME_INTERPOLATION_MODE_NEAREST;
|
||||
}
|
||||
|
||||
Field<float3> position_field = params.extract_input<Field<float3>>("Position");
|
||||
auto fn = std::make_shared<SampleVolumeFunction>(std::move(base_grid), interpolation_mode);
|
||||
auto op = FieldOperation::Create(std::move(fn), {position_field});
|
||||
GField output_field = GField(std::move(op));
|
||||
|
||||
output_field = bke::get_implicit_type_conversions().try_convert(
|
||||
output_field, *bke::custom_data_type_to_cpp_type(output_field_type));
|
||||
|
||||
output_attribute_field(params, std::move(output_field));
|
||||
#else
|
||||
params.set_default_remaining_outputs();
|
||||
params.error_message_add(NodeWarningType::Error,
|
||||
TIP_("Disabled, Blender was compiled without OpenVDB"));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace blender::nodes::node_geo_sample_volume_cc
|
||||
|
||||
void register_node_type_geo_sample_volume()
|
||||
{
|
||||
namespace file_ns = blender::nodes::node_geo_sample_volume_cc;
|
||||
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_SAMPLE_VOLUME, "Sample Volume", NODE_CLASS_CONVERTER);
|
||||
node_type_storage(
|
||||
&ntype, "NodeGeometrySampleVolume", node_free_standard_storage, node_copy_standard_storage);
|
||||
ntype.initfunc = file_ns::node_init;
|
||||
ntype.updatefunc = file_ns::node_update;
|
||||
ntype.declare = file_ns::node_declare;
|
||||
ntype.geometry_node_execute = file_ns::node_geo_exec;
|
||||
ntype.draw_buttons = file_ns::node_layout;
|
||||
ntype.gather_add_node_search_ops = file_ns::search_node_add_ops;
|
||||
ntype.gather_link_search_ops = file_ns::search_link_ops;
|
||||
ntype.geometry_node_execute = file_ns::node_geo_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
Reference in New Issue
Block a user