diff options
Diffstat (limited to 'source/blender/nodes')
24 files changed, 897 insertions, 192 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 1e7ac4b92f6..ac2200d496b 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -142,6 +142,7 @@ set(SRC function/node_function_util.cc geometry/nodes/node_geo_align_rotation_to_vector.cc + geometry/nodes/node_geo_attribute_capture.cc geometry/nodes/node_geo_attribute_clamp.cc geometry/nodes/node_geo_attribute_color_ramp.cc geometry/nodes/node_geo_attribute_combine_xyz.cc @@ -187,6 +188,9 @@ set(SRC geometry/nodes/node_geo_delete_geometry.cc geometry/nodes/node_geo_edge_split.cc geometry/nodes/node_geo_input_material.cc + geometry/nodes/node_geo_input_normal.cc + geometry/nodes/node_geo_input_position.cc + geometry/nodes/node_geo_input_index.cc geometry/nodes/node_geo_is_viewport.cc geometry/nodes/node_geo_join_geometry.cc geometry/nodes/node_geo_material_assign.cc @@ -212,6 +216,7 @@ set(SRC geometry/nodes/node_geo_raycast.cc geometry/nodes/node_geo_select_by_material.cc geometry/nodes/node_geo_separate_components.cc + geometry/nodes/node_geo_set_position.cc geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_switch.cc geometry/nodes/node_geo_transform.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 00062400eee..e9fb4ad123c 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -37,6 +37,7 @@ void register_node_type_geo_attribute_compare(void); void register_node_type_geo_attribute_convert(void); void register_node_type_geo_attribute_curve_map(void); void register_node_type_geo_attribute_fill(void); +void register_node_type_geo_attribute_capture(void); void register_node_type_geo_attribute_map_range(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_attribute_mix(void); @@ -71,7 +72,10 @@ void register_node_type_geo_curve_to_points(void); void register_node_type_geo_curve_trim(void); void register_node_type_geo_delete_geometry(void); void register_node_type_geo_edge_split(void); +void register_node_type_geo_input_index(void); void register_node_type_geo_input_material(void); +void register_node_type_geo_input_normal(void); +void register_node_type_geo_input_position(void); void register_node_type_geo_is_viewport(void); void register_node_type_geo_join_geometry(void); void register_node_type_geo_material_assign(void); @@ -99,6 +103,7 @@ void register_node_type_geo_sample_texture(void); void register_node_type_geo_select_by_handle_type(void); void register_node_type_geo_select_by_material(void); void register_node_type_geo_separate_components(void); +void register_node_type_geo_set_position(void); void register_node_type_geo_subdivision_surface(void); void register_node_type_geo_switch(void); void register_node_type_geo_transform(void); diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index d6a23051c0b..e0972e40a64 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -16,7 +16,8 @@ #pragma once -#include "FN_generic_value_map.hh" +#include "FN_field.hh" +#include "FN_multi_function_builder.hh" #include "BKE_attribute_access.hh" #include "BKE_geometry_set.hh" @@ -32,17 +33,24 @@ struct ModifierData; namespace blender::nodes { +using bke::AttributeIDRef; using bke::geometry_set_realize_instances; +using bke::GeometryComponentFieldContext; using bke::OutputAttribute; using bke::OutputAttribute_Typed; using bke::ReadAttributeLookup; +using bke::StrongAnonymousAttributeID; +using bke::WeakAnonymousAttributeID; using bke::WriteAttributeLookup; using fn::CPPType; +using fn::Field; +using fn::FieldInput; +using fn::FieldOperation; +using fn::GField; using fn::GMutablePointer; using fn::GMutableSpan; using fn::GPointer; using fn::GSpan; -using fn::GValueMap; using fn::GVArray; using fn::GVArray_GSpan; using fn::GVArray_Span; @@ -121,6 +129,14 @@ class GeoNodeExecParams { { } + template<typename T> + static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> || + std::is_same_v<T, int> || + std::is_same_v<T, bool> || + std::is_same_v<T, ColorGeometry4f> || + std::is_same_v<T, float3> || + std::is_same_v<T, std::string>; + /** * Get the input value for the input socket with the given identifier. * @@ -142,11 +158,17 @@ class GeoNodeExecParams { */ template<typename T> T extract_input(StringRef identifier) { + if constexpr (is_stored_as_field_v<T>) { + Field<T> field = this->extract_input<Field<T>>(identifier); + return fn::evaluate_constant_field(field); + } + else { #ifdef DEBUG - this->check_input_access(identifier, &CPPType::get<T>()); + this->check_input_access(identifier, &CPPType::get<T>()); #endif - GMutablePointer gvalue = this->extract_input(identifier); - return gvalue.relocate_out<T>(); + GMutablePointer gvalue = this->extract_input(identifier); + return gvalue.relocate_out<T>(); + } } /** @@ -159,7 +181,13 @@ class GeoNodeExecParams { Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier); Vector<T> values; for (GMutablePointer gvalue : gvalues) { - values.append(gvalue.relocate_out<T>()); + if constexpr (is_stored_as_field_v<T>) { + const Field<T> &field = *gvalue.get<Field<T>>(); + values.append(fn::evaluate_constant_field(field)); + } + else { + values.append(gvalue.relocate_out<T>()); + } } return values; } @@ -167,14 +195,20 @@ class GeoNodeExecParams { /** * Get the input value for the input socket with the given identifier. */ - template<typename T> const T &get_input(StringRef identifier) const + template<typename T> const T get_input(StringRef identifier) const { + if constexpr (is_stored_as_field_v<T>) { + const Field<T> &field = this->get_input<Field<T>>(identifier); + return fn::evaluate_constant_field(field); + } + else { #ifdef DEBUG - this->check_input_access(identifier, &CPPType::get<T>()); + this->check_input_access(identifier, &CPPType::get<T>()); #endif - GPointer gvalue = provider_->get_input(identifier); - BLI_assert(gvalue.is_type<T>()); - return *(const T *)gvalue.get(); + GPointer gvalue = provider_->get_input(identifier); + BLI_assert(gvalue.is_type<T>()); + return *(const T *)gvalue.get(); + } } /** @@ -183,13 +217,19 @@ class GeoNodeExecParams { template<typename T> void set_output(StringRef identifier, T &&value) { using StoredT = std::decay_t<T>; - const CPPType &type = CPPType::get<std::decay_t<T>>(); + if constexpr (is_stored_as_field_v<StoredT>) { + this->set_output<Field<StoredT>>(identifier, + fn::make_constant_field<StoredT>(std::forward<T>(value))); + } + else { + const CPPType &type = CPPType::get<StoredT>(); #ifdef DEBUG - this->check_output_access(identifier, type); + this->check_output_access(identifier, type); #endif - GMutablePointer gvalue = provider_->alloc_output_value(type); - new (gvalue.get()) StoredT(std::forward<T>(value)); - provider_->set_output(identifier, gvalue); + GMutablePointer gvalue = provider_->alloc_output_value(type); + new (gvalue.get()) StoredT(std::forward<T>(value)); + provider_->set_output(identifier, gvalue); + } } /** diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 2e9f186de02..670cde4470e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -276,6 +276,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CONVERT, def_geo_attribute_convert, "ATTRIBUTE_CONVERT", AttributeConvert, "Attribute Convert", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CURVE_MAP, def_geo_attribute_curve_map, "ATTRIBUTE_CURVE_MAP", AttributeCurveMap, "Attribute Curve Map", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CAPTURE, def_geo_attribute_capture, "ATTRIBUTE_CAPTURE", AttributeCapture, "Attribute Capture", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "") @@ -304,8 +305,8 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRA DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "") DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "") DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "") -DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "") DefNode(GeometryNode, GEO_NODE_CURVE_SELECT_HANDLES, def_geo_curve_select_handles, "CURVE_SELECT_HANDLES", CurveSelectHandles, "Select by Handle Type", "") +DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "") DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "") DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "") DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "") @@ -313,7 +314,10 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_ DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "") DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "") +DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "") +DefNode(GeometryNode, GEO_NODE_INPUT_NORMAL, 0, "INPUT_NORMAL", InputNormal, "Normal", "") +DefNode(GeometryNode, GEO_NODE_INPUT_POSITION, 0, "POSITION", InputPosition, "Position", "") DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "") DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "") DefNode(GeometryNode, GEO_NODE_MATERIAL_ASSIGN, 0, "MATERIAL_ASSIGN", MaterialAssign, "Material Assign", "") @@ -339,6 +343,7 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POIN DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "") DefNode(GeometryNode, GEO_NODE_SELECT_BY_MATERIAL, 0, "SELECT_BY_MATERIAL", SelectByMaterial, "Select by Material", "") DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "") +DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Set Position", "") DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 6a69c3d24ec..015ac0de002 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -84,7 +84,7 @@ struct CurveToPointsResults { MutableSpan<float> radii; MutableSpan<float> tilts; - Map<std::string, GMutableSpan> point_attributes; + Map<AttributeIDRef, GMutableSpan> point_attributes; MutableSpan<float3> tangents; MutableSpan<float3> normals; 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 ¶ms, } 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); +} diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 7487f11d77d..3b3b643d0ae 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -161,8 +161,10 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful { bke::geometry_set_instances_attribute_foreach( geometry_set, - [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) { - this->attributes_.append({attribute_name, meta_data.domain, meta_data.data_type}); + [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + if (attribute_id.is_named()) { + this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type}); + } return true; }, 8); diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index d386781e3ce..8efd6c55459 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -48,6 +48,7 @@ #include "NOD_socket.h" #include "FN_cpp_type_make.hh" +#include "FN_field.hh" using namespace blender; using blender::nodes::SocketDeclarationPtr; @@ -701,8 +702,14 @@ static bNodeSocketType *make_socket_type_bool() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; - socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + socktype->get_geometry_nodes_cpp_type = []() { + return &blender::fn::CPPType::get<blender::fn::Field<bool>>(); + }; + socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { + bool value; + socket.typeinfo->get_base_cpp_value(socket, &value); + new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + }; return socktype; } @@ -713,8 +720,14 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; - socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + socktype->get_geometry_nodes_cpp_type = []() { + return &blender::fn::CPPType::get<blender::fn::Field<float>>(); + }; + socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { + float value; + socket.typeinfo->get_base_cpp_value(socket, &value); + new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + }; return socktype; } @@ -725,8 +738,14 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; - socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + socktype->get_geometry_nodes_cpp_type = []() { + return &blender::fn::CPPType::get<blender::fn::Field<int>>(); + }; + socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { + int value; + socket.typeinfo->get_base_cpp_value(socket, &value); + new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + }; return socktype; } @@ -737,8 +756,14 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; - socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + socktype->get_geometry_nodes_cpp_type = []() { + return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); + }; + socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { + blender::float3 value; + socket.typeinfo->get_base_cpp_value(socket, &value); + new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + }; return socktype; } @@ -751,8 +776,15 @@ static bNodeSocketType *make_socket_type_rgba() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; - socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + socktype->get_geometry_nodes_cpp_type = []() { + return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); + }; + socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { + blender::ColorGeometry4f value; + socket.typeinfo->get_base_cpp_value(socket, &value); + new (r_value) + blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + }; return socktype; } @@ -763,8 +795,15 @@ static bNodeSocketType *make_socket_type_string() socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; - socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; + socktype->get_geometry_nodes_cpp_type = []() { + return &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); + }; + socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { + std::string value; + value.~basic_string(); + socket.typeinfo->get_base_cpp_value(socket, &value); + new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + }; return socktype; } |