Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_set_position.cc
| Show All 17 Lines | |||||
| #include "node_geometry_util.hh" | #include "node_geometry_util.hh" | ||||
| namespace blender::nodes { | namespace blender::nodes { | ||||
| static void geo_node_set_position_declare(NodeDeclarationBuilder &b) | static void geo_node_set_position_declare(NodeDeclarationBuilder &b) | ||||
| { | { | ||||
| b.add_input<decl::Geometry>("Geometry"); | b.add_input<decl::Geometry>("Geometry"); | ||||
| b.add_input<decl::Vector>("Position").implicit_field(); | |||||
| b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field(); | b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field(); | ||||
| b.add_input<decl::Vector>("Position").implicit_field(); | |||||
| b.add_input<decl::Bool>("Offset").default_value(false).supports_field(); | |||||
| b.add_output<decl::Geometry>("Geometry"); | b.add_output<decl::Geometry>("Geometry"); | ||||
| } | } | ||||
| static void set_position_in_component(GeometryComponent &component, | static void set_position_in_component(GeometryComponent &component, | ||||
| const Field<bool> &selection_field, | const Field<bool> &selection_field, | ||||
| const Field<float3> &position_field) | const Field<float3> &position_field, | ||||
| const Field<bool> &offset_field) | |||||
| { | { | ||||
| GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; | GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; | ||||
| const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); | const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); | ||||
| if (domain_size == 0) { | if (domain_size == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| fn::FieldEvaluator selection_evaluator{field_context, domain_size}; | fn::FieldEvaluator selection_evaluator{field_context, domain_size}; | ||||
| selection_evaluator.add(selection_field); | selection_evaluator.add(selection_field); | ||||
| selection_evaluator.evaluate(); | selection_evaluator.evaluate(); | ||||
| const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); | const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); | ||||
| OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( | OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( | ||||
| "position", ATTR_DOMAIN_POINT, {0, 0, 0}); | "position", ATTR_DOMAIN_POINT, {0, 0, 0}); | ||||
| Array<float3> positions_input(domain_size); | |||||
| MutableSpan<float3> position_mutable = positions.as_span(); | |||||
HooglyBoogly: Since the offsets is usually probably just a single true or false value, it's probably best to… | |||||
| fn::FieldEvaluator position_evaluator{field_context, &selection}; | fn::FieldEvaluator position_evaluator{field_context, &selection}; | ||||
| position_evaluator.add_with_destination(position_field, positions.varray()); | position_evaluator.add_with_destination(position_field, positions_input.as_mutable_span()); | ||||
| position_evaluator.add(offset_field); | |||||
| position_evaluator.evaluate(); | position_evaluator.evaluate(); | ||||
| /* TODO: We could have different code paths depending on whether the offset input is a single | |||||
| * value or not */ | |||||
| const VArray<bool> &offsets_input = position_evaluator.get_evaluated<bool>(1); | |||||
| for (int i : selection) { | |||||
| position_mutable[i] = offsets_input[i] ? position_mutable[i] + positions_input[i] : | |||||
| positions_input[i]; | |||||
| } | |||||
| positions.save(); | positions.save(); | ||||
| } | } | ||||
| static void geo_node_set_position_exec(GeoNodeExecParams params) | static void geo_node_set_position_exec(GeoNodeExecParams params) | ||||
| { | { | ||||
| GeometrySet geometry = params.extract_input<GeometrySet>("Geometry"); | GeometrySet geometry = params.extract_input<GeometrySet>("Geometry"); | ||||
| Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); | Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); | ||||
| Field<bool> offset_field = params.extract_input<Field<bool>>("Offset"); | |||||
| Field<float3> position_field = params.extract_input<Field<float3>>("Position"); | Field<float3> position_field = params.extract_input<Field<float3>>("Position"); | ||||
| for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH, | for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH, | ||||
| GEO_COMPONENT_TYPE_POINT_CLOUD, | GEO_COMPONENT_TYPE_POINT_CLOUD, | ||||
| GEO_COMPONENT_TYPE_CURVE, | GEO_COMPONENT_TYPE_CURVE, | ||||
| GEO_COMPONENT_TYPE_INSTANCES}) { | GEO_COMPONENT_TYPE_INSTANCES}) { | ||||
| if (geometry.has(type)) { | if (geometry.has(type)) { | ||||
| set_position_in_component( | set_position_in_component( | ||||
| geometry.get_component_for_write(type), selection_field, position_field); | geometry.get_component_for_write(type), selection_field, position_field, offset_field); | ||||
| } | } | ||||
| } | } | ||||
| params.set_output("Geometry", std::move(geometry)); | params.set_output("Geometry", std::move(geometry)); | ||||
| } | } | ||||
| } // namespace blender::nodes | } // namespace blender::nodes | ||||
| Show All 9 Lines | |||||
Since the offsets is usually probably just a single true or false value, it's probably best to use a virtual array here:
VArray<bool> = position_evaluator.get_evaluated<bool>(1);
Same probably goes for position, but mostly because creating a temporary array involves an extra copy here when we don't really need it.
In the future we could have different code paths depending on whether the offset input is a single value or not, maybe it's worth noting that in a comment.