Geometry Nodes: Support lists and grids in more function nodes

Now every function node except for "Sample UV Surface" supports
both list and grid outputs. Any grid or list input means the output also
has that type (combinations of grids and lists aren't supported).
However note that some nodes also have inputs that are always fields
evaluated on the target geometry.

There is still plenty of room for optimization. For grids and lists, all
the outputs will be computed, and every function node is evaluated
completely separately. It would be better to build a network similar to
fields and evaluate it lazily (when topology doesn't change anyway).

Pull Request: https://projects.blender.org/blender/blender/pulls/147312
This commit is contained in:
Hans Goudey
2025-10-08 19:49:03 +02:00
committed by Hans Goudey
parent 66dd8beef3
commit a60e0cd44b
13 changed files with 361 additions and 135 deletions

View File

@@ -46,11 +46,34 @@ template<typename T> constexpr bool is_GeoNodesMultiInput_v<GeoNodesMultiInput<T
*/
[[nodiscard]] bool execute_multi_function_on_value_variant(
const mf::MultiFunction &fn,
const std::shared_ptr<mf::MultiFunction> &owned_fn,
Span<bke::SocketValueVariant *> input_values,
Span<bke::SocketValueVariant *> output_values,
GeoNodesUserData *user_data,
std::string &r_error_message);
[[nodiscard]] inline bool execute_multi_function_on_value_variant(
const std::shared_ptr<mf::MultiFunction> &owned_fn,
const Span<bke::SocketValueVariant *> input_values,
const Span<bke::SocketValueVariant *> output_values,
GeoNodesUserData *user_data,
std::string &r_error_message);
std::string &r_error_message)
{
const mf::MultiFunction &fn = *owned_fn;
return execute_multi_function_on_value_variant(
fn, std::move(owned_fn), input_values, output_values, user_data, r_error_message);
}
[[nodiscard]] inline bool execute_multi_function_on_value_variant(
const mf::MultiFunction &fn,
const Span<bke::SocketValueVariant *> input_values,
const Span<bke::SocketValueVariant *> output_values,
GeoNodesUserData *user_data,
std::string &r_error_message)
{
return execute_multi_function_on_value_variant(
fn, {}, input_values, output_values, user_data, r_error_message);
}
/**
* Performs implicit conversion between socket types. Returns false if the conversion is not

View File

@@ -39,6 +39,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR)
.supports_field()
.structure_type(StructureType::Dynamic)
.make_available([](bNode &node) {
node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_FACTOR;
});
@@ -46,13 +47,15 @@ static void node_declare(NodeDeclarationBuilder &b)
.min(0.0f)
.subtype(PROP_DISTANCE)
.supports_field()
.structure_type(StructureType::Dynamic)
.make_available([](bNode &node) {
node_storage(node).mode = GEO_NODE_CURVE_SAMPLE_LENGTH;
});
auto &index =
b.add_input<decl::Int>("Curve Index").supports_field().make_available([](bNode &node) {
node_storage(node).use_all_curves = false;
});
auto &index = b.add_input<decl::Int>("Curve Index")
.supports_field()
.structure_type(StructureType::Dynamic)
.make_available(
[](bNode &node) { node_storage(node).use_all_curves = false; });
if (const bNode *node = b.node_or_null()) {
const NodeGeometryCurveSample &storage = node_storage(*node);
@@ -480,43 +483,83 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometryCurveSample &storage = node_storage(params.node());
const GeometryNodeCurveSampleMode mode = GeometryNodeCurveSampleMode(storage.mode);
Field<float> length_field = params.extract_input<Field<float>>(
mode == GEO_NODE_CURVE_SAMPLE_FACTOR ? "Factor" : "Length");
const StringRef length_input_name = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ? "Factor" : "Length";
auto sample_length = params.extract_input<bke::SocketValueVariant>(length_input_name);
GField src_values_field = params.extract_input<GField>("Value");
std::string error_message;
bke::SocketValueVariant position;
bke::SocketValueVariant tangent;
bke::SocketValueVariant normal;
bke::SocketValueVariant value;
std::shared_ptr<FieldOperation> sample_op;
if (curves.curves_num() == 1) {
sample_op = FieldOperation::from(
std::make_unique<SampleCurveFunction>(
std::move(geometry_set), mode, std::move(src_values_field)),
{fn::make_constant_field<int>(0), std::move(length_field)});
auto curve_index = bke::SocketValueVariant::From(fn::make_constant_field<int>(0));
if (!execute_multi_function_on_value_variant(
std::make_unique<SampleCurveFunction>(
std::move(geometry_set), mode, std::move(src_values_field)),
{&curve_index, &sample_length},
{&position, &tangent, &normal, &value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
}
else {
if (storage.use_all_curves) {
auto index_fn = std::make_unique<SampleFloatSegmentsFunction>(
curve_accumulated_lengths(curves), mode);
auto index_op = FieldOperation::from(std::move(index_fn), {std::move(length_field)});
Field<int> curve_index = Field<int>(index_op, 0);
Field<float> length_in_curve = Field<float>(index_op, 1);
sample_op = FieldOperation::from(
std::make_unique<SampleCurveFunction>(
std::move(geometry_set), GEO_NODE_CURVE_SAMPLE_LENGTH, std::move(src_values_field)),
{std::move(curve_index), std::move(length_in_curve)});
bke::SocketValueVariant curve_index;
bke::SocketValueVariant length_in_curve;
if (!execute_multi_function_on_value_variant(std::make_unique<SampleFloatSegmentsFunction>(
curve_accumulated_lengths(curves), mode),
{&sample_length},
{&curve_index, &length_in_curve},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleCurveFunction>(std::move(geometry_set),
GEO_NODE_CURVE_SAMPLE_LENGTH,
std::move(src_values_field)),
{&curve_index, &length_in_curve},
{&position, &tangent, &normal, &value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
}
else {
Field<int> curve_index = params.extract_input<Field<int>>("Curve Index");
Field<float> length_in_curve = std::move(length_field);
sample_op = FieldOperation::from(
std::make_unique<SampleCurveFunction>(
std::move(geometry_set), mode, std::move(src_values_field)),
{std::move(curve_index), std::move(length_in_curve)});
auto curve_index = params.extract_input<bke::SocketValueVariant>("Curve Index");
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleCurveFunction>(
std::move(geometry_set), mode, std::move(src_values_field)),
{&curve_index, &sample_length},
{&position, &tangent, &normal, &value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
}
}
params.set_output("Position", Field<float3>(sample_op, 0));
params.set_output("Tangent", Field<float3>(sample_op, 1));
params.set_output("Normal", Field<float3>(sample_op, 2));
params.set_output("Value", GField(sample_op, 3));
params.set_output("Position", std::move(position));
params.set_output("Tangent", std::move(tangent));
params.set_output("Normal", std::move(normal));
params.set_output("Value", std::move(value));
}
static void node_register()

View File

@@ -407,12 +407,21 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
Field<float3> vector_field = params.extract_input<Field<float3>>("Vector");
auto sample_uv = params.extract_input<bke::SocketValueVariant>("Vector");
auto image_op = FieldOperation::from(std::move(image_fn), {std::move(vector_field)});
std::string error_message;
bke::SocketValueVariant color;
bke::SocketValueVariant alpha;
if (!execute_multi_function_on_value_variant(
std::move(image_fn), {&sample_uv}, {&color, &alpha}, params.user_data(), error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Color", Field<ColorGeometry4f>(image_op, 0));
params.set_output("Alpha", Field<float>(image_op, 1));
params.set_output("Color", std::move(color));
params.set_output("Alpha", std::move(alpha));
}
static void node_register()

View File

@@ -124,14 +124,15 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
auto fn_ptr = std::make_shared<SampleIndexFunction>(std::move(list));
const mf::MultiFunction &fn = *fn_ptr;
bke::SocketValueVariant output_value;
std::string error_message;
const bool success = execute_multi_function_on_value_variant(
fn, std::move(fn_ptr), {&index}, {&output_value}, params.user_data(), error_message);
if (!success) {
bke::SocketValueVariant output_value;
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleIndexFunction>(std::move(list)),
{&index},
{&output_value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;

View File

@@ -270,18 +270,32 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const NodeGeometryProximity &storage = node_storage(params.node());
const auto target_type = GeometryNodeProximityTargetType(storage.target_element);
Field<int> group_id_field = params.extract_input<Field<int>>("Group ID");
Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
Field<int> sample_id_field = params.extract_input<Field<int>>("Sample Group ID");
auto sample_position = params.extract_input<bke::SocketValueVariant>("Source Position");
auto sample_group_id = params.extract_input<bke::SocketValueVariant>("Sample Group ID");
auto proximity_fn = std::make_unique<ProximityFunction>(
std::move(target), GeometryNodeProximityTargetType(storage.target_element), group_id_field);
auto proximity_op = FieldOperation::from(
std::move(proximity_fn), {std::move(position_field), std::move(sample_id_field)});
std::string error_message;
bke::SocketValueVariant position;
bke::SocketValueVariant distance;
bke::SocketValueVariant is_valid;
if (!execute_multi_function_on_value_variant(
std::make_shared<ProximityFunction>(
std::move(target), target_type, std::move(group_id_field)),
{&sample_position, &sample_group_id},
{&position, &distance, &is_valid},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Position", Field<float3>(proximity_op, 0));
params.set_output("Distance", Field<float>(proximity_op, 1));
params.set_output("Is Valid", Field<bool>(proximity_op, 2));
params.set_output("Position", std::move(position));
params.set_output("Distance", std::move(distance));
params.set_output("Is Valid", std::move(is_valid));
}
static void node_rna(StructRNA *srna)

View File

@@ -244,48 +244,105 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
static auto normalize_fn = mf::build::SI1_SO<float3, float3>(
"Normalize",
[](const float3 &v) { return math::normalize(v); },
mf::build::exec_presets::AllSpanOrSingle());
auto direction_op = FieldOperation::from(normalize_fn,
{params.extract_input<Field<float3>>("Ray Direction")});
std::string error_message;
auto op = FieldOperation::from(std::make_unique<RaycastFunction>(target),
{params.extract_input<Field<float3>>("Source Position"),
Field<float3>(direction_op),
params.extract_input<Field<float>>("Ray Length")});
bke::SocketValueVariant normalized_direction;
{
auto ray_direction = params.extract_input<bke::SocketValueVariant>("Ray Direction");
Field<float3> hit_position(op, 1);
params.set_output("Is Hit", Field<bool>(op, 0));
static auto normalize_fn = mf::build::SI1_SO<float3, float3>(
"Normalize",
[](const float3 &v) { return math::normalize(v); },
mf::build::exec_presets::AllSpanOrSingle());
if (!execute_multi_function_on_value_variant(normalize_fn,
{&ray_direction},
{&normalized_direction},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
}
auto position = params.extract_input<bke::SocketValueVariant>("Source Position");
auto ray_length = params.extract_input<bke::SocketValueVariant>("Ray Length");
bke::SocketValueVariant is_hit;
bke::SocketValueVariant hit_position;
bke::SocketValueVariant hit_normal;
bke::SocketValueVariant hit_distance;
bke::SocketValueVariant triangle_index;
if (!execute_multi_function_on_value_variant(
std::make_unique<RaycastFunction>(target),
{&position, &normalized_direction, &ray_length},
{&is_hit, &hit_position, &hit_normal, &hit_distance, &triangle_index},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Is Hit", std::move(is_hit));
params.set_output("Hit Position", hit_position);
params.set_output("Hit Normal", Field<float3>(op, 2));
params.set_output("Hit Distance", Field<float>(op, 3));
params.set_output("Hit Normal", std::move(hit_normal));
params.set_output("Hit Distance", std::move(hit_distance));
if (!params.output_is_required("Attribute")) {
return;
}
GField field = params.extract_input<GField>("Attribute");
Field<int> triangle_index(op, 4);
Field<float3> bary_weights;
bke::SocketValueVariant bary_weights;
bke::SocketValueVariant triangle_index_copy = triangle_index;
switch (mapping) {
case GEO_NODE_RAYCAST_INTERPOLATED:
bary_weights = Field<float3>(FieldOperation::from(
std::make_shared<bke::mesh_surface_sample::BaryWeightFromPositionFn>(target),
{hit_position, triangle_index}));
if (!execute_multi_function_on_value_variant(
std::make_shared<bke::mesh_surface_sample::BaryWeightFromPositionFn>(target),
{&hit_position, &triangle_index_copy},
{&bary_weights},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
break;
case GEO_NODE_RAYCAST_NEAREST:
bary_weights = Field<float3>(FieldOperation::from(
std::make_shared<bke::mesh_surface_sample::CornerBaryWeightFromPositionFn>(target),
{hit_position, triangle_index}));
if (!execute_multi_function_on_value_variant(
std::make_shared<bke::mesh_surface_sample::CornerBaryWeightFromPositionFn>(target),
{&hit_position, &triangle_index_copy},
{&bary_weights},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
break;
}
auto sample_op = FieldOperation::from(
std::make_shared<bke::mesh_surface_sample::BaryWeightSampleFn>(std::move(target),
std::move(field)),
{triangle_index, bary_weights});
params.set_output("Attribute", GField(sample_op));
bke::SocketValueVariant sampled_atribute;
if (!execute_multi_function_on_value_variant(
std::make_shared<bke::mesh_surface_sample::BaryWeightSampleFn>(std::move(target),
std::move(field)),
{&triangle_index, &bary_weights},
{&sampled_atribute},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Attribute", std::move(sampled_atribute));
}
static void node_rna(StructRNA *srna)

View File

@@ -227,24 +227,30 @@ class SampleGridFunction : public mf::MultiFunction {
static void node_geo_exec(GeoNodeExecParams params)
{
#ifdef WITH_OPENVDB
const bNode &node = params.node();
const eNodeSocketDatatype data_type = eNodeSocketDatatype(node.custom1);
const auto interpolation = params.get_input<InterpolationMode>("Interpolation");
bke::GVolumeGrid grid = params.extract_input<bke::GVolumeGrid>("Grid");
if (!grid) {
params.set_default_remaining_outputs();
return;
}
auto fn = std::make_shared<SampleGridFunction>(std::move(grid), interpolation);
auto op = FieldOperation::from(std::move(fn), {params.extract_input<Field<float3>>("Position")});
const auto interpolation = params.get_input<InterpolationMode>("Interpolation");
bke::SocketValueVariant position = params.extract_input<bke::SocketValueVariant>("Position");
const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
const CPPType &output_type = *bke::socket_type_to_geo_nodes_base_cpp_type(data_type);
const GField output_field = conversions.try_convert(fn::GField(std::move(op)), output_type);
params.set_output("Value", std::move(output_field));
std::string error_message;
bke::SocketValueVariant output_value;
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleGridFunction>(std::move(grid), interpolation),
{&position},
{&output_value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Value", std::move(output_value));
#else
node_geo_exec_with_missing_openvdb(params);
#endif

View File

@@ -194,26 +194,31 @@ class SampleGridIndexFunction : public mf::MultiFunction {
static void node_geo_exec(GeoNodeExecParams params)
{
#ifdef WITH_OPENVDB
const bNode &node = params.node();
const eNodeSocketDatatype data_type = eNodeSocketDatatype(node.custom1);
bke::GVolumeGrid grid = params.extract_input<bke::GVolumeGrid>("Grid");
if (!grid) {
params.set_default_remaining_outputs();
return;
}
auto fn = std::make_shared<SampleGridIndexFunction>(std::move(grid));
auto op = FieldOperation::from(std::move(fn),
{params.extract_input<Field<int>>("X"),
params.extract_input<Field<int>>("Y"),
params.extract_input<Field<int>>("Z")});
auto x = params.extract_input<bke::SocketValueVariant>("X");
auto y = params.extract_input<bke::SocketValueVariant>("Y");
auto z = params.extract_input<bke::SocketValueVariant>("Z");
const bke::DataTypeConversions &conversions = bke::get_implicit_type_conversions();
const CPPType &output_type = *bke::socket_type_to_geo_nodes_base_cpp_type(data_type);
const GField output_field = conversions.try_convert(fn::GField(std::move(op)), output_type);
params.set_output("Value", std::move(output_field));
std::string error_message;
bke::SocketValueVariant output_value;
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleGridIndexFunction>(std::move(grid)),
{&x, &y, &z},
{&output_value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Value", std::move(output_value));
#else
node_geo_exec_with_missing_openvdb(params);
#endif

View File

@@ -206,14 +206,12 @@ static void node_geo_exec(GeoNodeExecParams params)
SocketValueVariant index_value_variant = params.extract_input<SocketValueVariant>("Index");
const CPPType &cpp_type = value_field.cpp_type();
if (index_value_variant.is_context_dependent_field()) {
/* If the index is a field, the output has to be a field that still depends on the input. */
auto fn = std::make_shared<SampleIndexFunction>(
std::move(geometry), std::move(value_field), domain, use_clamp);
auto op = FieldOperation::from(std::move(fn), {index_value_variant.extract<Field<int>>()});
params.set_output("Value", GField(std::move(op)));
}
else if (const GeometryComponent *component = find_source_component(geometry, domain)) {
if (index_value_variant.is_single()) {
const GeometryComponent *component = find_source_component(geometry, domain);
if (!component) {
params.set_default_remaining_outputs();
return;
}
/* Optimization for the case when the index is a single value. Here only that one index has to
* be evaluated. */
const int domain_size = component->attribute_domain_size(domain);
@@ -236,11 +234,25 @@ static void node_geo_exec(GeoNodeExecParams params)
else {
params.set_output("Value", fn::make_constant_field(cpp_type, cpp_type.default_value()));
}
return;
}
else {
/* Output default value if there is no geometry. */
params.set_output("Value", fn::make_constant_field(cpp_type, cpp_type.default_value()));
bke::SocketValueVariant output_value;
std::string error_message;
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleIndexFunction>(
std::move(geometry), std::move(value_field), domain, use_clamp),
{&index_value_variant},
{&output_value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Value", std::move(output_value));
}
static void node_register()

View File

@@ -311,10 +311,23 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
Field<float3> positions = params.extract_input<Field<float3>>("Sample Position");
auto fn = std::make_shared<SampleNearestFunction>(std::move(geometry), domain);
auto op = FieldOperation::from(std::move(fn), {std::move(positions)});
params.set_output<Field<int>>("Index", Field<int>(std::move(op)));
auto sample_position = params.extract_input<bke::SocketValueVariant>("Sample Position");
std::string error_message;
bke::SocketValueVariant index;
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleNearestFunction>(std::move(geometry), domain),
{&sample_position},
{&index},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Index", std::move(index));
}
static void node_rna(StructRNA *srna)

View File

@@ -203,26 +203,58 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
auto nearest_op = FieldOperation::from(
std::make_shared<SampleNearestSurfaceFunction>(geometry,
params.extract_input<Field<int>>("Group ID")),
{params.extract_input<Field<float3>>("Sample Position"),
params.extract_input<Field<int>>("Sample Group ID")});
Field<int> triangle_indices(nearest_op, 0);
Field<float3> nearest_positions(nearest_op, 1);
Field<bool> is_valid(nearest_op, 2);
GField value = params.extract_input<GField>("Value");
Field<int> group_id_field = params.extract_input<Field<int>>("Group ID");
auto sample_position = params.extract_input<bke::SocketValueVariant>("Sample Position");
auto sample_group_id = params.extract_input<bke::SocketValueVariant>("Sample Group ID");
Field<float3> bary_weights = Field<float3>(FieldOperation::from(
std::make_shared<bke::mesh_surface_sample::BaryWeightFromPositionFn>(geometry),
{nearest_positions, triangle_indices}));
std::string error_message;
GField field = params.extract_input<GField>("Value");
auto sample_op = FieldOperation::from(
std::make_shared<bke::mesh_surface_sample::BaryWeightSampleFn>(geometry, std::move(field)),
{triangle_indices, bary_weights});
bke::SocketValueVariant triangle_index;
bke::SocketValueVariant nearest_positions;
bke::SocketValueVariant is_valid;
if (!execute_multi_function_on_value_variant(
std::make_shared<SampleNearestSurfaceFunction>(geometry, group_id_field),
{&sample_position, &sample_group_id},
{&triangle_index, &nearest_positions, &is_valid},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Value", GField(sample_op));
params.set_output("Is Valid", is_valid);
bke::SocketValueVariant bary_weights;
bke::SocketValueVariant triangle_index_copy = triangle_index;
if (!execute_multi_function_on_value_variant(
std::make_shared<bke::mesh_surface_sample::BaryWeightFromPositionFn>(geometry),
{&nearest_positions, &triangle_index_copy},
{&bary_weights},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
bke::SocketValueVariant sample_value;
if (!execute_multi_function_on_value_variant(
std::make_shared<bke::mesh_surface_sample::BaryWeightSampleFn>(geometry,
std::move(value)),
{&triangle_index, &bary_weights},
{&sample_value},
params.user_data(),
error_message))
{
params.set_default_remaining_outputs();
params.error_message_add(NodeWarningType::Error, std::move(error_message));
return;
}
params.set_output("Value", std::move(sample_value));
params.set_output("Is Valid", std::move(is_valid));
}
static void node_rna(StructRNA *srna)

View File

@@ -166,8 +166,19 @@ static void node_geo_exec(GeoNodeExecParams params)
const CPPType &float2_type = CPPType::get<float2>();
Field<float2> source_uv_map = conversions.try_convert(
params.extract_input<Field<float3>>("Source UV Map"), float2_type);
Field<float2> sample_uvs = conversions.try_convert(
params.extract_input<Field<float3>>("Sample UV"), float2_type);
auto sample_uv_value = params.extract_input<bke::SocketValueVariant>("Sample UV");
if (sample_uv_value.is_list()) {
params.error_message_add(NodeWarningType::Error,
"Lists are not supported for \"Sample UV\" input");
}
if (sample_uv_value.is_volume_grid()) {
params.error_message_add(NodeWarningType::Error,
"Volume grids are not supported for \"Sample UV\" input");
}
Field<float2> sample_uvs = conversions.try_convert(sample_uv_value.extract<Field<float3>>(),
float2_type);
auto uv_op = FieldOperation::from(
std::make_shared<ReverseUVSampleFunction>(geometry, std::move(source_uv_map)),
{std::move(sample_uvs)});

View File

@@ -557,7 +557,7 @@ std::optional<SocketValueVariant> implicitly_convert_socket_value(
SocketValueVariant output_variant;
std::string error_message;
if (!execute_multi_function_on_value_variant(
multi_fn, {}, {&input_variant}, {&output_variant}, nullptr, error_message))
multi_fn, {&input_variant}, {&output_variant}, nullptr, error_message))
{
return std::nullopt;
}
@@ -588,7 +588,7 @@ class LazyFunctionForImplicitConversion : public LazyFunction {
BLI_assert(to_value != nullptr);
std::string error_message;
if (!execute_multi_function_on_value_variant(
fn_, {}, {from_value}, {to_value}, nullptr, error_message))
fn_, {from_value}, {to_value}, nullptr, error_message))
{
std::destroy_at(to_value);
construct_socket_default_value(dst_type_, to_value);