diff options
11 files changed, 339 insertions, 147 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 66466e3972e..f57765e373b 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -760,6 +760,24 @@ class AttributeFieldInput : public fn::FieldInput { bool is_equal_to(const fn::FieldNode &other) const override; }; +class IDAttributeFieldInput : public fn::FieldInput { + public: + IDAttributeFieldInput() : fn::FieldInput(CPPType::get<int>()) + { + } + + static fn::Field<int> Create(); + + const GVArray *get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; + + std::string socket_inspection_name() const override; + + uint64_t hash() const override; + bool is_equal_to(const fn::FieldNode &other) const override; +}; + class AnonymousAttributeFieldInput : public fn::FieldInput { private: /** diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index d0510e0008e..930cabafb00 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -345,11 +345,18 @@ GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read( return {}; } - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_get_layer(custom_data, stored_type_); + const void *data; + if (stored_as_named_attribute_) { + data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()); + } + else { + data = CustomData_get_layer(custom_data, stored_type_); + } if (data == nullptr) { return {}; } + + const int domain_size = component.attribute_domain_size(domain_); return as_read_attribute_(data, domain_size); } @@ -368,11 +375,21 @@ GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write( if (data == nullptr) { return {}; } - void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); + + void *new_data; + if (stored_as_named_attribute_) { + new_data = CustomData_duplicate_referenced_layer_named( + custom_data, stored_type_, name_.c_str(), domain_size); + } + else { + new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); + } + if (data != new_data) { custom_data_access_.update_custom_data_pointers(component); data = new_data; } + if (update_on_write_ != nullptr) { update_on_write_(component); } @@ -390,7 +407,19 @@ bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) co } const int domain_size = component.attribute_domain_size(domain_); - const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); + int layer_index; + if (stored_as_named_attribute_) { + for (const int i : IndexRange(custom_data->totlayer)) { + if (custom_data_layer_matches_attribute_id(custom_data->layers[i], name_)) { + layer_index = i; + break; + } + } + } + else { + layer_index = CustomData_get_layer_index(custom_data, stored_type_); + } + const bool delete_success = CustomData_free_layer( custom_data, stored_type_, domain_size, layer_index); if (delete_success) { @@ -409,14 +438,25 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component, if (custom_data == nullptr) { return false; } - if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { - /* Exists already. */ - return false; - } const int domain_size = component.attribute_domain_size(domain_); - const bool success = add_builtin_type_custom_data_layer_from_init( - *custom_data, stored_type_, domain_size, initializer); + bool success; + if (stored_as_named_attribute_) { + if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) { + /* Exists already. */ + return false; + } + success = add_custom_data_layer_from_attribute_init( + name_, *custom_data, stored_type_, domain_size, initializer); + } + else { + if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { + /* Exists already. */ + return false; + } + success = add_builtin_type_custom_data_layer_from_init( + *custom_data, stored_type_, domain_size, initializer); + } if (success) { custom_data_access_.update_custom_data_pointers(component); } @@ -429,8 +469,10 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) if (custom_data == nullptr) { return false; } - const void *data = CustomData_get_layer(custom_data, stored_type_); - return data != nullptr; + if (stored_as_named_attribute_) { + return CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()) != nullptr; + } + return CustomData_get_layer(custom_data, stored_type_) != nullptr; } ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( @@ -1353,6 +1395,54 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return false; } +static StringRef get_random_id_attribute_name(const AttributeDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + return "id"; + default: + return ""; + } +} + +const GVArray *IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const +{ + if (const GeometryComponentFieldContext *geometry_context = + dynamic_cast<const GeometryComponentFieldContext *>(&context)) { + const GeometryComponent &component = geometry_context->geometry_component(); + const AttributeDomain domain = geometry_context->domain(); + const StringRef name = get_random_id_attribute_name(domain); + GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); + if (attribute) { + BLI_assert(attribute->size() == component.attribute_domain_size(domain)); + return scope.add(std::move(attribute)); + } + + /* Use the index as the fallback if no random ID attribute exists. */ + return fn::IndexFieldInput::get_index_varray(mask, scope); + } + return nullptr; +} + +std::string IDAttributeFieldInput::socket_inspection_name() const +{ + return TIP_("ID / Index"); +} + +uint64_t IDAttributeFieldInput::hash() const +{ + /* All random ID attribute inputs are the same within the same evaluation context. */ + return 92386459827; +} + +bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + /* All random ID attribute inputs are the same within the same evaluation context. */ + return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; +} + const GVArray *AnonymousAttributeFieldInput::get_varray_for_context( const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const { diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 6e5cdd6faba..5cedcf69953 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -227,6 +227,9 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { * This provider is used to provide access to builtin attributes. It supports making internal types * available as different types. For example, the vertex position attribute is stored as part of * the #MVert struct, but is exposed as float3 attribute. + * + * It also supports named builtin attributes, and will look up attributes in #CustomData by name + * if the stored type is the same as the attribute type. */ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); @@ -238,6 +241,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; const UpdateOnWrite update_on_write_; + bool stored_as_named_attribute_; public: BuiltinCustomDataLayerProvider(std::string attribute_name, @@ -257,7 +261,8 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { custom_data_access_(custom_data_access), as_read_attribute_(as_read_attribute), as_write_attribute_(as_write_attribute), - update_on_write_(update_on_write) + update_on_write_(update_on_write), + stored_as_named_attribute_(data_type_ == stored_type_) { } diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 50c0f06b12c..c3d7eff4e6f 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -623,6 +623,103 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data, } } +static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, + const CustomDataType data_type, + const Span<SplinePtr> splines) +{ + switch (initializer.type) { + case AttributeInit::Type::Default: + /* This function shouldn't be called in this case, since there + * is no need to copy anything to the new custom data array. */ + BLI_assert_unreachable(); + return {}; + case AttributeInit::Type::VArray: + return static_cast<const AttributeInitVArray &>(initializer).varray->shallow_copy(); + case AttributeInit::Type::MoveArray: + int total_size = 0; + for (const SplinePtr &spline : splines) { + total_size += spline->size(); + } + return std::make_unique<fn::GVArray_For_GSpan>( + GSpan(*bke::custom_data_type_to_cpp_type(data_type), + static_cast<const AttributeInitMove &>(initializer).data, + total_size)); + } + BLI_assert_unreachable(); + return {}; +} + +static bool create_point_attribute(GeometryComponent &component, + const AttributeIDRef &attribute_id, + const AttributeInit &initializer, + const CustomDataType data_type) +{ + CurveEval *curve = get_curve_from_component_for_write(component); + if (curve == nullptr || curve->splines().size() == 0) { + return false; + } + + MutableSpan<SplinePtr> splines = curve->splines(); + + /* First check the one case that allows us to avoid copying the input data. */ + if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) { + void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) { + MEM_freeN(source_data); + return false; + } + return true; + } + + /* Otherwise just create a custom data layer on each of the splines. */ + for (const int i : splines.index_range()) { + if (!splines[i]->attributes.create(attribute_id, data_type)) { + /* If attribute creation fails on one of the splines, we cannot leave the custom data + * layers in the previous splines around, so delete them before returning. However, + * this is not an expected case. */ + BLI_assert_unreachable(); + return false; + } + } + + /* With a default initializer type, we can keep the values at their initial values. */ + if (initializer.type == AttributeInit::Type::Default) { + return true; + } + + WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id); + /* We just created the attribute, it should exist. */ + BLI_assert(write_attribute); + + GVArrayPtr source_varray = varray_from_initializer(initializer, data_type, splines); + /* TODO: When we can call a variant of #set_all with a virtual array argument, + * this theoretically unnecessary materialize step could be removed. */ + GVArray_GSpan source_varray_span{*source_varray}; + write_attribute.varray->set_all(source_varray_span.data()); + + if (initializer.type == AttributeInit::Type::MoveArray) { + MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); + } + + return true; +} + +static bool remove_point_attribute(GeometryComponent &component, + const AttributeIDRef &attribute_id) +{ + CurveEval *curve = get_curve_from_component_for_write(component); + if (curve == nullptr) { + return false; + } + + /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */ + bool layer_freed = false; + for (SplinePtr &spline : curve->splines()) { + layer_freed = spline->attributes.remove(attribute_id); + } + return layer_freed; +} + /** * Virtual array for any control point data accessed with spans and an offset array. */ @@ -980,15 +1077,17 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu public: BuiltinPointAttributeProvider(std::string attribute_name, + const CreatableEnum creatable, + const DeletableEnum deletable, const GetSpan get_span, const GetMutableSpan get_mutable_span, const UpdateOnWrite update_on_write) : BuiltinAttributeProvider(std::move(attribute_name), ATTR_DOMAIN_POINT, bke::cpp_type_to_custom_data_type(CPPType::get<T>()), - CreatableEnum::NonCreatable, + creatable, WritableEnum::Writable, - DeletableEnum::NonDeletable), + deletable), get_span_(get_span), get_mutable_span_(get_mutable_span), update_on_write_(update_on_write) @@ -1041,15 +1140,20 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu return point_data_gvarray(spans, offsets); } - bool try_delete(GeometryComponent &UNUSED(component)) const final + bool try_delete(GeometryComponent &component) const final { - return false; + if (deletable_ == DeletableEnum::NonDeletable) { + return false; + } + return remove_point_attribute(component, name_); } - bool try_create(GeometryComponent &UNUSED(component), - const AttributeInit &UNUSED(initializer)) const final + bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final { - return false; + if (createable_ == CreatableEnum::NonCreatable) { + return false; + } + return create_point_attribute(component, name_, initializer, CD_PROP_INT32); } bool exists(const GeometryComponent &component) const final @@ -1064,6 +1168,10 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu return false; } + if (!curve->splines().first()->attributes.get_for_read(name_)) { + return false; + } + bool has_point = false; for (const SplinePtr &spline : curve->splines()) { if (spline->size() != 0) { @@ -1090,6 +1198,8 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo PositionAttributeProvider() : BuiltinPointAttributeProvider( "position", + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::NonDeletable, [](const Spline &spline) { return spline.positions(); }, [](Spline &spline) { return spline.positions(); }, [](Spline &spline) { spline.mark_cache_invalid(); }) @@ -1319,39 +1429,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final { - CurveEval *curve = get_curve_from_component_for_write(component); - if (curve == nullptr) { - return false; - } - - /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */ - bool layer_freed = false; - for (SplinePtr &spline : curve->splines()) { - layer_freed = spline->attributes.remove(attribute_id); - } - return layer_freed; - } - - static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, - const CustomDataType data_type, - const int total_size) - { - switch (initializer.type) { - case AttributeInit::Type::Default: - /* This function shouldn't be called in this case, since there - * is no need to copy anything to the new custom data array. */ - BLI_assert_unreachable(); - return {}; - case AttributeInit::Type::VArray: - return static_cast<const AttributeInitVArray &>(initializer).varray->shallow_copy(); - case AttributeInit::Type::MoveArray: - return std::make_unique<fn::GVArray_For_GSpan>( - GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast<const AttributeInitMove &>(initializer).data, - total_size)); - } - BLI_assert_unreachable(); - return {}; + return remove_point_attribute(component, attribute_id); } bool try_create(GeometryComponent &component, @@ -1364,55 +1442,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { if (domain != ATTR_DOMAIN_POINT) { return false; } - CurveEval *curve = get_curve_from_component_for_write(component); - if (curve == nullptr || curve->splines().size() == 0) { - return false; - } - - MutableSpan<SplinePtr> splines = curve->splines(); - - /* First check the one case that allows us to avoid copying the input data. */ - if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; - if (!splines[0]->attributes.create_by_move(attribute_id, data_type, source_data)) { - MEM_freeN(source_data); - return false; - } - return true; - } - - /* Otherwise just create a custom data layer on each of the splines. */ - for (const int i : splines.index_range()) { - if (!splines[i]->attributes.create(attribute_id, data_type)) { - /* If attribute creation fails on one of the splines, we cannot leave the custom data - * layers in the previous splines around, so delete them before returning. However, - * this is not an expected case. */ - BLI_assert_unreachable(); - return false; - } - } - - /* With a default initializer type, we can keep the values at their initial values. */ - if (initializer.type == AttributeInit::Type::Default) { - return true; - } - - WriteAttributeLookup write_attribute = this->try_get_for_write(component, attribute_id); - /* We just created the attribute, it should exist. */ - BLI_assert(write_attribute); - - const int total_size = curve->control_point_offsets().last(); - GVArrayPtr source_varray = varray_from_initializer(initializer, data_type, total_size); - /* TODO: When we can call a variant of #set_all with a virtual array argument, - * this theoretically unnecessary materialize step could be removed. */ - GVArray_GSpan source_varray_span{*source_varray}; - write_attribute.varray->set_all(source_varray_span.data()); - - if (initializer.type == AttributeInit::Type::MoveArray) { - MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); - } - - return true; + return create_point_attribute(component, attribute_id, initializer, data_type); } bool foreach_attribute(const GeometryComponent &component, @@ -1487,14 +1517,32 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() static BezierHandleAttributeProvider handles_start(false); static BezierHandleAttributeProvider handles_end(true); + static BuiltinPointAttributeProvider<int> id( + "id", + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Deletable, + [](const Spline &spline) { + std::optional<GSpan> span = spline.attributes.get_for_read("id"); + return span ? span->typed<int>() : Span<int>(); + }, + [](Spline &spline) { + std::optional<GMutableSpan> span = spline.attributes.get_for_write("id"); + return span ? span->typed<int>() : MutableSpan<int>(); + }, + {}); + static BuiltinPointAttributeProvider<float> radius( "radius", + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::NonDeletable, [](const Spline &spline) { return spline.radii(); }, [](Spline &spline) { return spline.radii(); }, nullptr); static BuiltinPointAttributeProvider<float> tilt( "tilt", + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::NonDeletable, [](const Spline &spline) { return spline.tilts(); }, [](Spline &spline) { return spline.tilts(); }, [](Spline &spline) { spline.mark_cache_invalid(); }); @@ -1502,7 +1550,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() static DynamicPointAttributeProvider point_custom_data; return ComponentAttributeProviders( - {&position, &radius, &tilt, &handles_start, &handles_end, &resolution, &cyclic}, + {&position, &id, &radius, &tilt, &handles_start, &handles_end, &resolution, &cyclic}, {&spline_custom_data, &point_custom_data}); } diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0c98aa5551b..6091d3f3dab 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -912,6 +912,19 @@ static GVMutableArrayPtr make_derived_write_attribute(void *data, const int doma MutableSpan<StructT>((StructT *)data, domain_size)); } +template<typename T> +static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); +} + +template<typename T> +static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +{ + return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( + MutableSpan<T>((T *)data, domain_size)); +} + static float3 get_vertex_position(const MVert &vert) { return float3(vert.co); @@ -1274,6 +1287,18 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static NormalAttributeProvider normal; + static BuiltinCustomDataLayerProvider id("id", + ATTR_DOMAIN_POINT, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr); + static BuiltinCustomDataLayerProvider material_index( "material_index", ATTR_DOMAIN_FACE, @@ -1335,14 +1360,15 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access); - return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease}, - {&uvs, - &vertex_colors, - &corner_custom_data, - &vertex_groups, - &point_custom_data, - &edge_custom_data, - &face_custom_data}); + return ComponentAttributeProviders( + {&position, &id, &material_index, &shade_smooth, &normal, &crease}, + {&uvs, + &vertex_colors, + &corner_custom_data, + &vertex_groups, + &point_custom_data, + &edge_custom_data, + &face_custom_data}); } } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index 6c4af7a6d23..dfb65a9078d 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -202,8 +202,19 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() make_array_read_attribute<float>, make_array_write_attribute<float>, nullptr); + static BuiltinCustomDataLayerProvider id("id", + ATTR_DOMAIN_POINT, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr); static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); + return ComponentAttributeProviders({&position, &radius, &id}, {&point_custom_data}); } } // namespace blender::bke diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 78a49e342a5..ed5064fdf25 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -418,6 +418,8 @@ class IndexFieldInput final : public FieldInput { public: IndexFieldInput(); + static GVArray *get_index_varray(IndexMask mask, ResourceScope &scope); + const GVArray *get_varray_for_context(const FieldContext &context, IndexMask mask, ResourceScope &scope) const final; diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 1f7bad134a8..c6125b65c5e 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -519,17 +519,22 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index") { } -const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const +GVArray *IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &scope) { - /* TODO: Investigate a similar method to IndexRange::as_span() */ auto index_func = [](int i) { return i; }; return &scope.construct< fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( mask.min_array_size(), mask.min_array_size(), index_func); } +const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &scope) const +{ + /* TODO: Investigate a similar method to IndexRange::as_span() */ + return get_index_varray(mask, scope); +} + uint64_t IndexFieldInput::hash() const { /* Some random constant hash. */ diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 0e7f5fe155b..51dd210c77a 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -335,8 +335,8 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) } const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()]; if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) { + const bNode &bnode = *socket.bnode(); if (socket.typeinfo()->type == SOCK_VECTOR) { - const bNode &bnode = *socket.bnode(); if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) { StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode == GEO_NODE_CURVE_HANDLE_LEFT ? @@ -349,6 +349,10 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) return true; } if (socket.typeinfo()->type == SOCK_INT) { + if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { + new (r_value) Field<int>(std::make_shared<bke::IDAttributeFieldInput>()); + return true; + } new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>()); return true; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 44beead86ad..0d481011f00 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -58,7 +58,6 @@ static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBui b.add_output<decl::Geometry>("Points"); b.add_output<decl::Vector>("Normal").field_source(); b.add_output<decl::Vector>("Rotation").subtype(PROP_EULER).field_source(); - b.add_output<decl::Int>("Stable ID").field_source(); } static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout, @@ -329,7 +328,6 @@ namespace { struct AttributeOutputs { StrongAnonymousAttributeID normal_id; StrongAnonymousAttributeID rotation_id; - StrongAnonymousAttributeID stable_id_id; }; } // namespace @@ -339,19 +337,16 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com const Span<int> looptri_indices, const AttributeOutputs &attribute_outputs) { - OutputAttribute_Typed<int> id_attribute; + OutputAttribute_Typed<int> id_attribute = point_component.attribute_try_get_for_output_only<int>( + "id", ATTR_DOMAIN_POINT); + MutableSpan<int> ids = id_attribute.as_span(); + OutputAttribute_Typed<float3> normal_attribute; OutputAttribute_Typed<float3> rotation_attribute; - MutableSpan<int> ids; MutableSpan<float3> normals; MutableSpan<float3> rotations; - if (attribute_outputs.stable_id_id) { - id_attribute = point_component.attribute_try_get_for_output_only<int>( - attribute_outputs.stable_id_id.get(), ATTR_DOMAIN_POINT); - ids = id_attribute.as_span(); - } if (attribute_outputs.normal_id) { normal_attribute = point_component.attribute_try_get_for_output_only<float3>( attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT); @@ -379,9 +374,8 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com const float3 v1_pos = float3(mesh.mvert[v1_index].co); const float3 v2_pos = float3(mesh.mvert[v2_index].co); - if (!ids.is_empty()) { - ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index); - } + ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index); + float3 normal; if (!normals.is_empty() || !rotations.is_empty()) { normal_tri_v3(normal, v0_pos, v1_pos, v2_pos); @@ -394,9 +388,8 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com } } - if (id_attribute) { - id_attribute.save(); - } + id_attribute.save(); + if (normal_attribute) { normal_attribute.save(); } @@ -512,6 +505,10 @@ static void point_distribution_calculate(GeometrySet &geometry_set, } } + if (positions.is_empty()) { + return; + } + PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size()); memcpy(pointcloud->co, positions.data(), sizeof(float3) * positions.size()); uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f); @@ -551,9 +548,6 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par if (params.output_is_required("Rotation")) { attribute_outputs.rotation_id = StrongAnonymousAttributeID("rotation"); } - if (params.output_is_required("Stable ID")) { - attribute_outputs.stable_id_id = StrongAnonymousAttributeID("stable id"); - } geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { point_distribution_calculate( @@ -575,11 +569,6 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par "Rotation", AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id))); } - if (attribute_outputs.stable_id_id) { - params.set_output( - "Stable ID", - AnonymousAttributeFieldInput::Create<int>(std::move(attribute_outputs.stable_id_id))); - } } } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index c7235fb2c29..78399fad2c0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -48,11 +48,6 @@ static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b) .subtype(PROP_XYZ) .supports_field() .description("Scale of the instances"); - b.add_input<decl::Int>("Stable ID") - .supports_field() - .description( - "ID for every instance that is used to identify it over time even when the number of " - "instances changes. Used for example for motion blur"); b.add_output<decl::Geometry>("Instances"); } @@ -91,12 +86,11 @@ static void add_instances_from_component(InstancesComponent &dst_component, const VArray<float3> *scales = nullptr; /* The evaluator could use the component's stable IDs as a destination directly, but only the * selected indices should be copied. */ - const VArray<int> *stable_ids = nullptr; + GVArray_Typed<int> stable_ids = src_component.attribute_get_for_read("id", ATTR_DOMAIN_POINT, 0); field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); field_evaluator.add(params.get_input<Field<int>>("Instance Index"), &indices); field_evaluator.add(params.get_input<Field<float3>>("Rotation"), &rotations); field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales); - field_evaluator.add(params.get_input<Field<int>>("Stable ID"), &stable_ids); field_evaluator.evaluate(); GVArray_Typed<float3> positions = src_component.attribute_get_for_read<float3>( |