Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh18
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc114
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh7
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc228
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc42
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc13
-rw-r--r--source/blender/functions/FN_field.hh2
-rw-r--r--source/blender/functions/intern/field.cc13
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc35
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc8
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>(