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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/geometry/nodes')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc210
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc51
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc82
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc60
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc211
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc90
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_separate.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc79
17 files changed, 769 insertions, 160 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
new file mode 100644
index 00000000000..1fa71d3f57d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -0,0 +1,210 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_attribute_math.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Vector>("Value");
+ b.add_input<decl::Float>("Value", "Value_001");
+ b.add_input<decl::Color>("Value", "Value_002");
+ b.add_input<decl::Bool>("Value", "Value_003");
+ b.add_input<decl::Int>("Value", "Value_004");
+
+ b.add_output<decl::Geometry>("Geometry");
+ b.add_output<decl::Vector>("Attribute");
+ b.add_output<decl::Float>("Attribute", "Attribute_001");
+ b.add_output<decl::Color>("Attribute", "Attribute_002");
+ b.add_output<decl::Bool>("Attribute", "Attribute_003");
+ b.add_output<decl::Int>("Attribute", "Attribute_004");
+}
+
+static void geo_node_attribute_capture_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+}
+
+static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
+ sizeof(NodeGeometryAttributeCapture), __func__);
+ data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_POINT;
+
+ node->storage = data;
+}
+
+static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
+ node->storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *socket_value_attribute_name = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *socket_value_vector = socket_value_attribute_name->next;
+ bNodeSocket *socket_value_float = socket_value_vector->next;
+ bNodeSocket *socket_value_color4f = socket_value_float->next;
+ bNodeSocket *socket_value_boolean = socket_value_color4f->next;
+ bNodeSocket *socket_value_int32 = socket_value_boolean->next;
+
+ nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32);
+
+ bNodeSocket *out_socket_value_attribute_name = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *out_socket_value_vector = out_socket_value_attribute_name->next;
+ bNodeSocket *out_socket_value_float = out_socket_value_vector->next;
+ bNodeSocket *out_socket_value_color4f = out_socket_value_float->next;
+ bNodeSocket *out_socket_value_boolean = out_socket_value_color4f->next;
+ bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next;
+
+ nodeSetSocketAvailability(out_socket_value_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(out_socket_value_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(out_socket_value_color4f, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(out_socket_value_boolean, data_type == CD_PROP_BOOL);
+ nodeSetSocketAvailability(out_socket_value_int32, data_type == CD_PROP_INT32);
+}
+
+static void try_capture_field_on_geometry(GeometryComponent &component,
+ const AttributeIDRef &attribute_id,
+ const AttributeDomain domain,
+ const GField &field)
+{
+ GeometryComponentFieldContext field_context{component, domain};
+ const int domain_size = component.attribute_domain_size(domain);
+ const IndexMask mask{IndexMask(domain_size)};
+
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
+ OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
+ attribute_id, domain, data_type);
+
+ fn::FieldEvaluator evaluator{field_context, &mask};
+ evaluator.add_with_destination(field, output_attribute.varray());
+ evaluator.evaluate();
+
+ output_attribute.save();
+}
+
+static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ const bNode &node = params.node();
+ const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
+ node.storage;
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+
+ GField field;
+ switch (data_type) {
+ case CD_PROP_FLOAT:
+ field = params.get_input<Field<float>>("Value_001");
+ break;
+ case CD_PROP_FLOAT3:
+ field = params.get_input<Field<float3>>("Value");
+ break;
+ case CD_PROP_COLOR:
+ field = params.get_input<Field<ColorGeometry4f>>("Value_002");
+ break;
+ case CD_PROP_BOOL:
+ field = params.get_input<Field<bool>>("Value_003");
+ break;
+ case CD_PROP_INT32:
+ field = params.get_input<Field<int>>("Value_004");
+ break;
+ default:
+ break;
+ }
+
+ WeakAnonymousAttributeID anonymous_id{"Attribute Capture"};
+ const CPPType &type = field.cpp_type();
+
+ static const Array<GeometryComponentType> types = {
+ GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE};
+ for (const GeometryComponentType type : types) {
+ if (geometry_set.has(type)) {
+ GeometryComponent &component = geometry_set.get_component_for_write(type);
+ try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ }
+ }
+
+ GField output_field{
+ std::make_shared<bke::AnonymousAttributeFieldInput>(std::move(anonymous_id), type)};
+
+ switch (data_type) {
+ case CD_PROP_FLOAT: {
+ params.set_output("Attribute_001", Field<float>(output_field));
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ params.set_output("Attribute", Field<float3>(output_field));
+ break;
+ }
+ case CD_PROP_COLOR: {
+ params.set_output("Attribute_002", Field<ColorGeometry4f>(output_field));
+ break;
+ }
+ case CD_PROP_BOOL: {
+ params.set_output("Attribute_003", Field<bool>(output_field));
+ break;
+ }
+ case CD_PROP_INT32: {
+ params.set_output("Attribute_004", Field<int>(output_field));
+ break;
+ }
+ default:
+ break;
+ }
+
+ params.set_output("Geometry", geometry_set);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_attribute_capture()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(
+ &ntype, GEO_NODE_ATTRIBUTE_CAPTURE, "Attribute Capture", NODE_CLASS_ATTRIBUTE, 0);
+ node_type_storage(&ntype,
+ "NodeGeometryAttributeCapture",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init);
+ node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update);
+ ntype.declare = blender::nodes::geo_node_attribute_capture_declare;
+ ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec;
+ ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc
index 699fcc5e983..7853c5aa04a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc
@@ -56,25 +56,26 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
Span<int> offsets,
PointCloudComponent &points)
{
- curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
- if (meta_data.domain != ATTR_DOMAIN_CURVE) {
- return true;
- }
- GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
- name, ATTR_DOMAIN_CURVE, meta_data.data_type);
-
- OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
- name, ATTR_DOMAIN_POINT, meta_data.data_type);
- GMutableSpan result = result_attribute.as_span();
-
- /* Only copy the attributes of splines in the offsets. */
- for (const int i : offsets.index_range()) {
- spline_attribute->get(offsets[i], result[i]);
- }
-
- result_attribute.save();
- return true;
- });
+ curve_component.attribute_foreach(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_CURVE) {
+ return true;
+ }
+ GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
+
+ OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
+ GMutableSpan result = result_attribute.as_span();
+
+ /* Only copy the attributes of splines in the offsets. */
+ for (const int i : offsets.index_range()) {
+ spline_attribute->get(offsets[i], result[i]);
+ }
+
+ result_attribute.save();
+ return true;
+ });
}
/**
@@ -124,20 +125,20 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines,
/* Copy the point attribute data over. */
for (const auto &item : start_data.point_attributes.items()) {
- const StringRef name = item.key;
+ const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
- BLI_assert(spline.attributes.get_for_read(name));
- GSpan spline_span = *spline.attributes.get_for_read(name);
+ BLI_assert(spline.attributes.get_for_read(attribute_id));
+ GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]);
}
for (const auto &item : end_data.point_attributes.items()) {
- const StringRef name = item.key;
+ const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
- BLI_assert(spline.attributes.get_for_read(name));
- GSpan spline_span = *spline.attributes.get_for_read(name);
+ BLI_assert(spline.attributes.get_for_read(attribute_id));
+ GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]);
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 1382efa025b..6f40687540c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -84,14 +84,14 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
input_spline.radii().first());
output_spline->attributes.reallocate(1);
input_spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = input_spline.attributes.get_for_read(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
BLI_assert(src);
- if (!output_spline->attributes.create(name, meta_data.data_type)) {
+ if (!output_spline->attributes.create(attribute_id, meta_data.data_type)) {
BLI_assert_unreachable();
return false;
}
- std::optional<GMutableSpan> dst = output_spline->attributes.get_for_write(name);
+ std::optional<GMutableSpan> dst = output_spline->attributes.get_for_write(attribute_id);
if (!dst) {
BLI_assert_unreachable();
return false;
@@ -122,15 +122,15 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
output_spline->attributes.reallocate(count);
input_spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
- std::optional<GSpan> input_attribute = input_spline.attributes.get_for_read(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> input_attribute = input_spline.attributes.get_for_read(attribute_id);
BLI_assert(input_attribute);
- if (!output_spline->attributes.create(name, meta_data.data_type)) {
+ if (!output_spline->attributes.create(attribute_id, meta_data.data_type)) {
BLI_assert_unreachable();
return false;
}
std::optional<GMutableSpan> output_attribute = output_spline->attributes.get_for_write(
- name);
+ attribute_id);
if (!output_attribute) {
BLI_assert_unreachable();
return false;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index b826e1c6510..720af50b795 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -83,9 +83,9 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
reverse_data<float>(splines[i]->tilts());
splines[i]->attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<blender::fn::GMutableSpan> output_attribute =
- splines[i]->attributes.get_for_write(name);
+ splines[i]->attributes.get_for_write(attribute_id);
if (!output_attribute) {
BLI_assert_unreachable();
return false;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index 6a093f442cb..6380873fbcb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -74,14 +74,14 @@ template<typename CopyFn>
static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
{
input_spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = input_spline.attributes.get_for_read(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
BLI_assert(src);
- if (!output_spline.attributes.create(name, meta_data.data_type)) {
+ if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
BLI_assert_unreachable();
return false;
}
- std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(name);
+ std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
if (!dst) {
BLI_assert_unreachable();
return false;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 958d83e2967..2809543a73d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -283,16 +283,16 @@ static void subdivide_dynamic_attributes(const Spline &src_spline,
{
const bool is_cyclic = src_spline.is_cyclic();
src_spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = src_spline.attributes.get_for_read(name);
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = src_spline.attributes.get_for_read(attribute_id);
BLI_assert(src);
- if (!dst_spline.attributes.create(name, meta_data.data_type)) {
+ if (!dst_spline.attributes.create(attribute_id, meta_data.data_type)) {
/* Since the source spline of the same type had the attribute, adding it should work. */
BLI_assert_unreachable();
}
- std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(name);
+ std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(attribute_id);
BLI_assert(dst);
attribute_math::convert_to_static_type(dst->type(), [&](auto dummy) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 17cd8e987a7..74740ba244f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -115,21 +115,21 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
}
static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
- const StringRef name,
+ const AttributeIDRef &attribute_id,
const CustomDataType data_type)
{
- points.attribute_try_create(name, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
- WriteAttributeLookup attribute = points.attribute_try_get_for_write(name);
+ points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
+ WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
BLI_assert(attribute);
return attribute.varray->get_internal_span();
}
template<typename T>
static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
- const StringRef name)
+ const AttributeIDRef &attribute_id)
{
GMutableSpan attribute = create_attribute_and_retrieve_span(
- points, name, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
+ points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
return attribute.typed<T>();
}
@@ -147,9 +147,10 @@ CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponen
/* Because of the invariants of the curve component, we use the attributes of the
* first spline as a representative for the attribute meta data all splines. */
curve.splines().first()->attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
attributes.point_attributes.add_new(
- name, create_attribute_and_retrieve_span(points, name, meta_data.data_type));
+ attribute_id,
+ create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
return true;
},
ATTR_DOMAIN_POINT);
@@ -179,12 +180,12 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size));
spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size));
- for (const Map<std::string, GMutableSpan>::Item &item : data.point_attributes.items()) {
- const StringRef name = item.key;
+ for (const Map<AttributeIDRef, GMutableSpan>::Item &item : data.point_attributes.items()) {
+ const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
- BLI_assert(spline.attributes.get_for_read(name));
- GSpan spline_span = *spline.attributes.get_for_read(name);
+ BLI_assert(spline.attributes.get_for_read(attribute_id));
+ GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
spline.interpolate_to_evaluated(spline_span)
->materialize(point_span.slice(offset, size).data());
@@ -222,12 +223,12 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
uniform_samples,
data.tilts.slice(offset, size));
- for (const Map<std::string, GMutableSpan>::Item &item : data.point_attributes.items()) {
- const StringRef name = item.key;
+ for (const Map<AttributeIDRef, GMutableSpan>::Item &item : data.point_attributes.items()) {
+ const AttributeIDRef attribute_id = item.key;
GMutableSpan point_span = item.value;
- BLI_assert(spline.attributes.get_for_read(name));
- GSpan spline_span = *spline.attributes.get_for_read(name);
+ BLI_assert(spline.attributes.get_for_read(attribute_id));
+ GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span),
uniform_samples,
@@ -257,31 +258,32 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
Span<int> offsets,
PointCloudComponent &points)
{
- curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
- if (meta_data.domain != ATTR_DOMAIN_CURVE) {
- return true;
- }
- GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
- name, ATTR_DOMAIN_CURVE, meta_data.data_type);
- const CPPType &type = spline_attribute->type();
-
- OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
- name, ATTR_DOMAIN_POINT, meta_data.data_type);
- GMutableSpan result = result_attribute.as_span();
-
- for (const int i : IndexRange(spline_attribute->size())) {
- const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
- if (size != 0) {
- BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
- spline_attribute->get(i, buffer);
- type.fill_assign_n(buffer, result[offset], size);
- }
- }
-
- result_attribute.save();
- return true;
- });
+ curve_component.attribute_foreach(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_CURVE) {
+ return true;
+ }
+ GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
+ attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
+ const CPPType &type = spline_attribute->type();
+
+ OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
+ attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
+ GMutableSpan result = result_attribute.as_span();
+
+ for (const int i : IndexRange(spline_attribute->size())) {
+ const int offset = offsets[i];
+ const int size = offsets[i + 1] - offsets[i];
+ if (size != 0) {
+ BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
+ spline_attribute->get(i, buffer);
+ type.fill_assign_n(buffer, result[offset], size);
+ }
+ }
+
+ result_attribute.save();
+ return true;
+ });
}
void curve_create_default_rotation_attribute(Span<float3> tangents,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 578f0298a19..4ad311d63c5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -158,8 +158,8 @@ static void trim_poly_spline(Spline &spline,
linear_trim_data<float>(start, end, spline.tilts());
spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
- std::optional<GMutableSpan> src = spline.attributes.get_for_write(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
+ std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
BLI_assert(src);
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -193,14 +193,14 @@ static PolySpline trim_nurbs_spline(const Spline &spline,
/* Copy generic attribute data. */
spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = spline.attributes.get_for_read(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
BLI_assert(src);
- if (!new_spline.attributes.create(name, meta_data.data_type)) {
+ if (!new_spline.attributes.create(attribute_id, meta_data.data_type)) {
BLI_assert_unreachable();
return false;
}
- std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(name);
+ std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
BLI_assert(dst);
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
@@ -249,8 +249,8 @@ static void trim_bezier_spline(Spline &spline,
linear_trim_data<float>(start, end, bezier_spline.radii());
linear_trim_data<float>(start, end, bezier_spline.tilts());
spline.attributes.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
- std::optional<GMutableSpan> src = spline.attributes.get_for_write(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
+ std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
BLI_assert(src);
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
using T = decltype(dummy);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 6bc0ab49959..b36b12d8cf5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -93,17 +93,17 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src,
const IndexMask mask)
{
src.foreach_attribute(
- [&](StringRefNull name, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src_attribute = src.get_for_read(name);
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src_attribute = src.get_for_read(attribute_id);
BLI_assert(src_attribute);
- if (!dst.create(name, meta_data.data_type)) {
+ if (!dst.create(attribute_id, meta_data.data_type)) {
/* Since the source spline of the same type had the attribute, adding it should work.
*/
BLI_assert_unreachable();
}
- std::optional<GMutableSpan> new_attribute = dst.get_for_write(name);
+ std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id);
BLI_assert(new_attribute);
attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
new file mode 100644
index 00000000000..e2287abe56c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_input_index_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Int>("Index");
+}
+
+class IndexFieldInput final : public fn::FieldInput {
+ public:
+ IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
+ {
+ }
+
+ const GVArray *get_varray_for_context(const fn::FieldContext &UNUSED(context),
+ IndexMask mask,
+ ResourceScope &scope) const final
+ {
+ /* 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)>>>(
+ __func__, mask.min_array_size(), mask.min_array_size(), index_func);
+ }
+};
+
+static void geo_node_input_index_exec(GeoNodeExecParams params)
+{
+ Field<int> index_field{std::make_shared<IndexFieldInput>()};
+ params.set_output("Index", std::move(index_field));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_input_index()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec;
+ ntype.declare = blender::nodes::geo_node_input_index_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
new file mode 100644
index 00000000000..b8f126ef1db
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -0,0 +1,211 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_input_normal_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>("Normal");
+}
+
+static GVArrayPtr mesh_face_normals(const Mesh &mesh,
+ const Span<MVert> verts,
+ const Span<MPoly> polys,
+ const Span<MLoop> loops,
+ const IndexMask mask)
+{
+ /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
+ if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
+ CustomData_has_layer(&mesh.pdata, CD_NORMAL)) {
+ const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
+
+ return std::make_unique<fn::GVArray_For_Span<float3>>(
+ Span<float3>((const float3 *)data, polys.size()));
+ }
+
+ auto normal_fn = [verts, polys, loops](const int i) -> float3 {
+ float3 normal;
+ const MPoly &poly = polys[i];
+ BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), normal);
+ return normal;
+ };
+
+ return std::make_unique<
+ fn::GVArray_For_EmbeddedVArray<float3, VArray_For_Func<float3, decltype(normal_fn)>>>(
+ mask.min_array_size(), mask.min_array_size(), normal_fn);
+}
+
+static GVArrayPtr mesh_vertex_normals(const Mesh &mesh,
+ const Span<MVert> verts,
+ const Span<MPoly> polys,
+ const Span<MLoop> loops,
+ const IndexMask mask)
+{
+ /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
+ if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) &&
+ CustomData_has_layer(&mesh.vdata, CD_NORMAL)) {
+ const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
+
+ return std::make_unique<fn::GVArray_For_Span<float3>>(
+ Span<float3>((const float3 *)data, mesh.totvert));
+ }
+
+ /* If the normals are dirty, they must be recalculated for the output of this node's field
+ * source. Ideally vertex normals could be calculated lazily on a const mesh, but that's not
+ * possible at the moment, so we take ownership of the results. Sadly we must also create a copy
+ * of MVert to use the mesh normals API. This can be improved by adding mutex-protected lazy
+ * calculation of normals on meshes.
+ *
+ * Use mask.min_array_size() to avoid calculating a final chunk of data if possible. */
+ Array<MVert> temp_verts(verts);
+ Array<float3> normals(verts.size()); /* Use full size for accumulation from faces. */
+ BKE_mesh_calc_normals_poly_and_vertex(temp_verts.data(),
+ mask.min_array_size(),
+ loops.data(),
+ loops.size(),
+ polys.data(),
+ polys.size(),
+ nullptr,
+ (float(*)[3])normals.data());
+
+ return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
+}
+
+static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_component,
+ const Mesh &mesh,
+ const IndexMask mask,
+ const AttributeDomain domain,
+ ResourceScope &scope)
+{
+ Span<MVert> verts{mesh.mvert, mesh.totvert};
+ Span<MEdge> edges{mesh.medge, mesh.totedge};
+ Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
+ Span<MLoop> loops{mesh.mloop, mesh.totloop};
+
+ switch (domain) {
+ case ATTR_DOMAIN_FACE: {
+ return scope.add_value(mesh_face_normals(mesh, verts, polys, loops, mask), __func__).get();
+ }
+ case ATTR_DOMAIN_POINT: {
+ return scope.add_value(mesh_vertex_normals(mesh, verts, polys, loops, mask), __func__).get();
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* In this case, start with vertex normals and convert to the edge domain, since the
+ * conversion from edges to vertices is very simple. Use the full mask since the edges
+ * might use the vertex normal from any index. */
+ GVArrayPtr vert_normals = mesh_vertex_normals(
+ mesh, verts, polys, loops, IndexRange(verts.size()));
+ Span<float3> vert_normals_span = vert_normals->get_internal_span().typed<float3>();
+ Array<float3> edge_normals(mask.min_array_size());
+
+ /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid
+ * calculating unnecessary values and to allow normalizing the result much more simply. */
+ for (const int i : mask) {
+ const MEdge &edge = edges[i];
+ edge_normals[i] = float3::interpolate(
+ vert_normals_span[edge.v1], vert_normals_span[edge.v2], 0.5f)
+ .normalized();
+ }
+
+ return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(
+ __func__, std::move(edge_normals));
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* The normals on corners are just the mesh's face normals, so start with the face normal
+ * array and copy the face normal for each of its corners. */
+ GVArrayPtr face_normals = mesh_face_normals(
+ mesh, verts, polys, loops, IndexRange(polys.size()));
+
+ /* In this case using the mesh component's generic domain interpolation is fine, the data
+ * will still be normalized, since the face normal is just copied to every corner. */
+ GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain(
+ std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
+ return scope.add_value(std::move(loop_normals), __func__).get();
+ }
+ default:
+ return nullptr;
+ }
+}
+
+class NormalFieldInput final : public fn::FieldInput {
+ public:
+ NormalFieldInput() : fn::FieldInput(CPPType::get<float3>(), "Normal")
+ {
+ }
+
+ const GVArray *get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const final
+ {
+ if (const GeometryComponentFieldContext *geometry_context =
+ dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
+
+ const GeometryComponent &component = geometry_context->geometry_component();
+ const AttributeDomain domain = geometry_context->domain();
+
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return nullptr;
+ }
+
+ return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope);
+ }
+ if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ /* TODO: Add curve normals support. */
+ return nullptr;
+ }
+ }
+ return nullptr;
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 669605641;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void geo_node_input_normal_exec(GeoNodeExecParams params)
+{
+ Field<float3> normal_field{std::make_shared<NormalFieldInput>()};
+ params.set_output("Normal", std::move(normal_field));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_input_normal()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec;
+ ntype.declare = blender::nodes::geo_node_input_normal_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
new file mode 100644
index 00000000000..c6365bf6809
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -0,0 +1,43 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_input_position_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>("Position");
+}
+
+static void geo_node_input_position_exec(GeoNodeExecParams params)
+{
+ Field<float3> position_field{
+ std::make_shared<bke::AttributeFieldInput>("position", CPPType::get<float3>())};
+ params.set_output("Position", std::move(position_field));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_input_position()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0);
+ ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec;
+ ntype.declare = blender::nodes::geo_node_input_position_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 730cf08feaa..5792ee1485a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -161,34 +161,35 @@ static Array<const GeometryComponent *> to_base_components(Span<const Component
return components;
}
-static Map<std::string, AttributeMetaData> get_final_attribute_info(
+static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
Span<const GeometryComponent *> components, Span<StringRef> ignored_attributes)
{
- Map<std::string, AttributeMetaData> info;
+ Map<AttributeIDRef, AttributeMetaData> info;
for (const GeometryComponent *component : components) {
- component->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
- if (ignored_attributes.contains(name)) {
- return true;
- }
- info.add_or_modify(
- name,
- [&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
- [&](AttributeMetaData *meta_data_final) {
- meta_data_final->data_type = blender::bke::attribute_data_type_highest_complexity(
- {meta_data_final->data_type, meta_data.data_type});
- meta_data_final->domain = blender::bke::attribute_domain_highest_priority(
- {meta_data_final->domain, meta_data.domain});
- });
- return true;
- });
+ component->attribute_foreach(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
+ return true;
+ }
+ info.add_or_modify(
+ attribute_id,
+ [&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
+ [&](AttributeMetaData *meta_data_final) {
+ meta_data_final->data_type = blender::bke::attribute_data_type_highest_complexity(
+ {meta_data_final->data_type, meta_data.data_type});
+ meta_data_final->domain = blender::bke::attribute_domain_highest_priority(
+ {meta_data_final->domain, meta_data.domain});
+ });
+ return true;
+ });
}
return info;
}
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
- StringRef attribute_name,
+ const AttributeIDRef &attribute_id,
const CustomDataType data_type,
const AttributeDomain domain,
GMutableSpan dst_span)
@@ -203,7 +204,7 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
continue;
}
GVArrayPtr read_attribute = component->attribute_get_for_read(
- attribute_name, domain, data_type, nullptr);
+ attribute_id, domain, data_type, nullptr);
GVArray_GSpan src_span{*read_attribute};
const void *src_buffer = src_span.data();
@@ -218,20 +219,21 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
GeometryComponent &result,
Span<StringRef> ignored_attributes = {})
{
- const Map<std::string, AttributeMetaData> info = get_final_attribute_info(src_components,
- ignored_attributes);
+ const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(src_components,
+ ignored_attributes);
- for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
- const StringRef name = item.key;
+ for (const Map<AttributeIDRef, AttributeMetaData>::Item &item : info.items()) {
+ const AttributeIDRef attribute_id = item.key;
const AttributeMetaData &meta_data = item.value;
OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
- name, meta_data.domain, meta_data.data_type);
+ attribute_id, meta_data.domain, meta_data.data_type);
if (!write_attribute) {
continue;
}
GMutableSpan dst_span = write_attribute.as_span();
- fill_new_attribute(src_components, name, meta_data.data_type, meta_data.domain, dst_span);
+ fill_new_attribute(
+ src_components, attribute_id, meta_data.data_type, meta_data.domain, dst_span);
write_attribute.save();
}
}
@@ -306,7 +308,7 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
* \note This takes advantage of the fact that creating attributes on joined curves never
* changes a point attribute into a spline attribute; it is always the other way around.
*/
-static void ensure_control_point_attribute(const StringRef name,
+static void ensure_control_point_attribute(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
Span<CurveComponent *> src_components,
CurveEval &result)
@@ -321,7 +323,7 @@ static void ensure_control_point_attribute(const StringRef name,
const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
for (SplinePtr &spline : splines) {
- std::optional<GSpan> attribute = spline->attributes.get_for_read(name);
+ std::optional<GSpan> attribute = spline->attributes.get_for_read(attribute_id);
if (attribute) {
if (attribute->type() != type) {
@@ -334,22 +336,22 @@ static void ensure_control_point_attribute(const StringRef name,
conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type)
->materialize(converted_buffer);
- spline->attributes.remove(name);
- spline->attributes.create_by_move(name, data_type, converted_buffer);
+ spline->attributes.remove(attribute_id);
+ spline->attributes.create_by_move(attribute_id, data_type, converted_buffer);
}
}
else {
- spline->attributes.create(name, data_type);
+ spline->attributes.create(attribute_id, data_type);
- if (current_curve->attributes.get_for_read(name)) {
+ if (current_curve->attributes.get_for_read(attribute_id)) {
/* In this case the attribute did not exist, but there is a spline domain attribute
* we can retrieve a value from, as a spline to point domain conversion. So fill the
* new attribute with the value for this spline. */
GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read(
- name, data_type, nullptr);
+ attribute_id, data_type, nullptr);
- BLI_assert(spline->attributes.get_for_read(name));
- std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(name);
+ BLI_assert(spline->attributes.get_for_read(attribute_id));
+ std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id);
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
current_curve_attribute->get(spline_index_in_component, buffer);
@@ -371,15 +373,15 @@ static void ensure_control_point_attribute(const StringRef name,
/**
* Fill data for an attribute on the new curve based on all source curves.
*/
-static void ensure_spline_attribute(const StringRef name,
+static void ensure_spline_attribute(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
Span<CurveComponent *> src_components,
CurveEval &result)
{
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- result.attributes.create(name, data_type);
- GMutableSpan result_attribute = *result.attributes.get_for_write(name);
+ result.attributes.create(attribute_id, data_type);
+ GMutableSpan result_attribute = *result.attributes.get_for_write(attribute_id);
int offset = 0;
for (const CurveComponent *component : src_components) {
@@ -388,7 +390,7 @@ static void ensure_spline_attribute(const StringRef name,
if (size == 0) {
continue;
}
- GVArrayPtr read_attribute = curve.attributes.get_for_read(name, data_type, nullptr);
+ GVArrayPtr read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr);
GVArray_GSpan src_span{*read_attribute};
const void *src_buffer = src_span.data();
@@ -406,19 +408,19 @@ static void ensure_spline_attribute(const StringRef name,
* \warning Splines have been moved out of the source components at this point, so it
* is important to only read curve-level data (spline domain attributes) from them.
*/
-static void join_curve_attributes(const Map<std::string, AttributeMetaData> &info,
+static void join_curve_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
Span<CurveComponent *> src_components,
CurveEval &result)
{
- for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
- const StringRef name = item.key;
+ for (const Map<AttributeIDRef, AttributeMetaData>::Item &item : info.items()) {
+ const AttributeIDRef attribute_id = item.key;
const AttributeMetaData meta_data = item.value;
if (meta_data.domain == ATTR_DOMAIN_CURVE) {
- ensure_spline_attribute(name, meta_data.data_type, src_components, result);
+ ensure_spline_attribute(attribute_id, meta_data.data_type, src_components, result);
}
else {
- ensure_control_point_attribute(name, meta_data.data_type, src_components, result);
+ ensure_control_point_attribute(attribute_id, meta_data.data_type, src_components, result);
}
}
}
@@ -446,7 +448,7 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
}
/* Retrieve attribute info before moving the splines out of the input components. */
- const Map<std::string, AttributeMetaData> info = get_final_attribute_info(
+ const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(
{(const GeometryComponent **)src_components.data(), src_components.size()},
{"position", "radius", "tilt", "cyclic", "resolution"});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 2cea60ea112..298c6fc1ffe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -52,10 +52,10 @@ static void copy_attributes_to_points(CurveEval &curve,
Span<Vector<int>> point_to_vert_maps)
{
MutableSpan<SplinePtr> splines = curve.splines();
- Set<std::string> source_attribute_names = mesh_component.attribute_names();
+ Set<AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
/* Copy builtin control point attributes. */
- if (source_attribute_names.contains_as("tilt")) {
+ if (source_attribute_ids.contains("tilt")) {
const GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
"tilt", ATTR_DOMAIN_POINT, 0.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
@@ -64,9 +64,9 @@ static void copy_attributes_to_points(CurveEval &curve,
*tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
}
});
- source_attribute_names.remove_contained_as("tilt");
+ source_attribute_ids.remove_contained("tilt");
}
- if (source_attribute_names.contains_as("radius")) {
+ if (source_attribute_ids.contains("radius")) {
const GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
"radius", ATTR_DOMAIN_POINT, 1.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
@@ -75,15 +75,15 @@ static void copy_attributes_to_points(CurveEval &curve,
*radius_attribute, point_to_vert_maps[i], splines[i]->radii());
}
});
- source_attribute_names.remove_contained_as("radius");
+ source_attribute_ids.remove_contained("radius");
}
/* Don't copy other builtin control point attributes. */
- source_attribute_names.remove_as("position");
+ source_attribute_ids.remove("position");
/* Copy dynamic control point attributes. */
- for (const StringRef name : source_attribute_names) {
- const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(name,
+ for (const AttributeIDRef &attribute_id : source_attribute_ids) {
+ const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id,
ATTR_DOMAIN_POINT);
/* Some attributes might not exist if they were builtin attribute on domains that don't
* have any elements, i.e. a face attribute on the output of the line primitive node. */
@@ -96,8 +96,9 @@ static void copy_attributes_to_points(CurveEval &curve,
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
/* Create attribute on the spline points. */
- splines[i]->attributes.create(name, data_type);
- std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(name);
+ splines[i]->attributes.create(attribute_id, data_type);
+ std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(
+ attribute_id);
BLI_assert(spline_attribute);
/* Copy attribute based on the map for this spline. */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index cf874bea718..dcab1ea3fb2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -277,17 +277,17 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
BLI_NOINLINE static void interpolate_existing_attributes(
Span<GeometryInstanceGroup> set_groups,
Span<int> instance_start_offsets,
- const Map<std::string, AttributeKind> &attributes,
+ const Map<AttributeIDRef, AttributeKind> &attributes,
GeometryComponent &component,
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
{
- for (Map<std::string, AttributeKind>::Item entry : attributes.items()) {
- StringRef attribute_name = entry.key;
+ for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
const CustomDataType output_data_type = entry.value.data_type;
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
OutputAttribute attribute_out = component.attribute_try_get_for_output_only(
- attribute_name, ATTR_DOMAIN_POINT, output_data_type);
+ attribute_id, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
continue;
}
@@ -301,7 +301,7 @@ BLI_NOINLINE static void interpolate_existing_attributes(
const Mesh &mesh = *source_component.get_for_read();
std::optional<AttributeMetaData> attribute_info = component.attribute_get_meta_data(
- attribute_name);
+ attribute_id);
if (!attribute_info) {
i_instance += set_group.transforms.size();
continue;
@@ -309,7 +309,7 @@ BLI_NOINLINE static void interpolate_existing_attributes(
const AttributeDomain source_domain = attribute_info->domain;
GVArrayPtr source_attribute = source_component.attribute_get_for_read(
- attribute_name, source_domain, output_data_type, nullptr);
+ attribute_id, source_domain, output_data_type, nullptr);
if (!source_attribute) {
i_instance += set_group.transforms.size();
continue;
@@ -406,7 +406,7 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
BLI_NOINLINE static void add_remaining_point_attributes(
Span<GeometryInstanceGroup> set_groups,
Span<int> instance_start_offsets,
- const Map<std::string, AttributeKind> &attributes,
+ const Map<AttributeIDRef, AttributeKind> &attributes,
GeometryComponent &component,
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
@@ -629,7 +629,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
PointCloudComponent &point_component =
geometry_set_out.get_component_for_write<PointCloudComponent>();
- Map<std::string, AttributeKind> attributes;
+ Map<AttributeIDRef, AttributeKind> attributes;
bke::geometry_set_gather_instances_attribute_info(
set_groups, {GEO_COMPONENT_TYPE_MESH}, {"position", "normal", "id"}, attributes);
add_remaining_point_attributes(set_groups,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
index 1b0061346c4..8752c1c669e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
@@ -53,8 +53,8 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
Span<bool> masks,
const bool invert)
{
- for (const std::string &name : in_component.attribute_names()) {
- ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name);
+ for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) {
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type());
/* Only copy point attributes. Theoretically this could interpolate attributes on other
@@ -65,7 +65,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
}
OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
- name, ATTR_DOMAIN_POINT, data_type);
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
new file mode 100644
index 00000000000..e8591616f55
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -0,0 +1,79 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DEG_depsgraph_query.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes {
+
+static void geo_node_set_position_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Geometry");
+ b.add_input<decl::Vector>("Position");
+ b.add_input<decl::Bool>("Selection").default_value(true);
+ b.add_output<decl::Geometry>("Geometry");
+}
+
+static void set_position_in_component(GeometryComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &position_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+
+ fn::FieldEvaluator selection_evaluator{field_context, domain_size};
+ selection_evaluator.add(selection_field);
+ selection_evaluator.evaluate();
+ const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+
+ OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+ fn::FieldEvaluator position_evaluator{field_context, &selection};
+ position_evaluator.add_with_destination(position_field, positions.varray());
+ position_evaluator.evaluate();
+ positions.save();
+}
+
+static void geo_node_set_position_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
+ geometry = geometry_set_realize_instances(geometry);
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ Field<float3> position_field = params.extract_input<Field<float3>>("Position");
+
+ for (const GeometryComponentType type :
+ {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) {
+ if (geometry.has(type)) {
+ set_position_in_component(
+ geometry.get_component_for_write(type), selection_field, position_field);
+ }
+ }
+
+ params.set_output("Geometry", std::move(geometry));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_set_position()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0);
+ ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec;
+ ntype.declare = blender::nodes::geo_node_set_position_declare;
+ nodeRegisterType(&ntype);
+}