diff options
Diffstat (limited to 'source/blender/nodes')
22 files changed, 193 insertions, 698 deletions
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 5d782674f16..58126c5722d 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -169,7 +169,7 @@ void ntreeCompositClearTags(struct bNodeTree *ntree); struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node, const char *name, - struct ImageFormatData *im_format); + const struct ImageFormatData *im_format); int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node); void ntreeCompositOutputFileSetPath(struct bNode *node, diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 7c7f114bb78..71d8f014399 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -64,7 +64,7 @@ DefNode(ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSD DefNode(ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "Physically-based, easy-to-use shader for rendering surface materials, based on the Disney principled model also known as the \"PBR\" shader") DefNode(ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "Reflection with microfacet distribution, used for materials such as metal or mirrors") DefNode(ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "Glass-like shader mixing refraction and reflection at grazing angles") -DefNode(ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "Glossy refraction with sharp or microfacet distribution,. Typically used for materials that transmit light") +DefNode(ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "Glossy refraction with sharp or microfacet distribution, typically used for materials that transmit light") DefNode(ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "Lambertian diffuse transmission") DefNode(ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "Transparency without refraction, passing straight through the surface as if there were no geometry") DefNode(ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "Reflection for materials such as cloth.\nTypically mixed with other shaders (such as a Diffuse Shader) and is not particularly useful on its own") diff --git a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc index 20dd61a9725..b87bbe439db 100644 --- a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc @@ -19,7 +19,7 @@ static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b) b.add_input<decl::Color>(N_("Image 1")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); b.add_input<decl::Color>(N_("Image 2")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); b.add_output<decl::Color>(N_("Image")); - b.add_output<decl::Color>(N_("Matte")); + b.add_output<decl::Float>(N_("Matte")); } static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc index f1621f83ac3..84235b085a4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc +++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc @@ -114,7 +114,7 @@ void ntreeCompositOutputFileUniqueLayer(ListBase *list, bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, - ImageFormatData *im_format) + const ImageFormatData *im_format) { NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; bNodeSocket *sock = nodeAddStaticSocket( diff --git a/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc index 0dfdeda24e6..df669d5beda 100644 --- a/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc @@ -49,7 +49,7 @@ namespace blender::nodes::node_composite_val_to_rgb_cc { static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); - b.add_output<decl::Color>(N_("Val")); + b.add_output<decl::Float>(N_("Val")); } } // namespace blender::nodes::node_composite_val_to_rgb_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc index 7e4904a7a6a..f6ea6073459 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc @@ -65,13 +65,12 @@ static void node_update(bNodeTree *ntree, bNode *node) static void node_geo_exec(GeoNodeExecParams params) { - GeometryComponentType component = (GeometryComponentType)params.node().custom1; - GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + const GeometryComponentType component = (GeometryComponentType)params.node().custom1; + const GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); switch (component) { case GEO_COMPONENT_TYPE_MESH: { - if (geometry_set.has_mesh()) { - const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); + if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) { const AttributeAccessor attributes = *component->attributes(); params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT)); params.set_output("Edge Count", attributes.domain_size(ATTR_DOMAIN_EDGE)); @@ -84,8 +83,8 @@ static void node_geo_exec(GeoNodeExecParams params) break; } case GEO_COMPONENT_TYPE_CURVE: { - if (geometry_set.has_curves()) { - const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>(); + if (const CurveComponent *component = + geometry_set.get_component_for_read<CurveComponent>()) { const AttributeAccessor attributes = *component->attributes(); params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT)); params.set_output("Spline Count", attributes.domain_size(ATTR_DOMAIN_CURVE)); @@ -96,10 +95,10 @@ static void node_geo_exec(GeoNodeExecParams params) break; } case GEO_COMPONENT_TYPE_POINT_CLOUD: { - if (geometry_set.has_pointcloud()) { - const PointCloudComponent *component = - geometry_set.get_component_for_read<PointCloudComponent>(); - params.set_output("Point Count", component->attributes()->domain_size(ATTR_DOMAIN_POINT)); + if (const PointCloudComponent *component = + geometry_set.get_component_for_read<PointCloudComponent>()) { + const AttributeAccessor attributes = *component->attributes(); + params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT)); } else { params.set_default_remaining_outputs(); @@ -107,11 +106,10 @@ static void node_geo_exec(GeoNodeExecParams params) break; } case GEO_COMPONENT_TYPE_INSTANCES: { - if (geometry_set.has_instances()) { - const InstancesComponent *component = - geometry_set.get_component_for_read<InstancesComponent>(); - params.set_output("Instance Count", - component->attributes()->domain_size(ATTR_DOMAIN_INSTANCE)); + if (const InstancesComponent *component = + geometry_set.get_component_for_read<InstancesComponent>()) { + const AttributeAccessor attributes = *component->attributes(); + params.set_output("Instance Count", attributes.domain_size(ATTR_DOMAIN_INSTANCE)); } else { params.set_default_remaining_outputs(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 489b618b8be..7c26ffc2099 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -140,28 +140,35 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) Span<float3> positions_span; - if (geometry_set.has_mesh()) { + if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) { count++; - const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); - const Mesh *mesh = component->get_for_read(); - total_num += mesh->totvert; + if (const VArray<float3> positions = component->attributes()->lookup<float3>( + "position", ATTR_DOMAIN_POINT)) { + if (positions.is_span()) { + span_count++; + positions_span = positions.get_internal_span(); + } + total_num += positions.size(); + } } - if (geometry_set.has_pointcloud()) { + if (const PointCloudComponent *component = + geometry_set.get_component_for_read<PointCloudComponent>()) { count++; - span_count++; - const PointCloudComponent *component = - geometry_set.get_component_for_read<PointCloudComponent>(); - const PointCloud *pointcloud = component->get_for_read(); - positions_span = {reinterpret_cast<const float3 *>(pointcloud->co), pointcloud->totpoint}; - total_num += pointcloud->totpoint; + if (const VArray<float3> positions = component->attributes()->lookup<float3>( + "position", ATTR_DOMAIN_POINT)) { + if (positions.is_span()) { + span_count++; + positions_span = positions.get_internal_span(); + } + total_num += positions.size(); + } } - if (geometry_set.has_curves()) { + if (const Curves *curves_id = geometry_set.get_curves_for_read()) { count++; span_count++; - const Curves &curves_id = *geometry_set.get_curves_for_read(); - const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); positions_span = curves.evaluated_positions(); total_num += positions_span.size(); } @@ -179,26 +186,25 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) Array<float3> positions(total_num); int offset = 0; - if (geometry_set.has_mesh()) { - const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); - const VArray<float3> varray = component->attributes()->lookup<float3>("position", - ATTR_DOMAIN_POINT); - varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); - offset += varray.size(); + if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) { + if (const VArray<float3> varray = component->attributes()->lookup<float3>("position", + ATTR_DOMAIN_POINT)) { + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); + offset += varray.size(); + } } - if (geometry_set.has_pointcloud()) { - const PointCloudComponent *component = - geometry_set.get_component_for_read<PointCloudComponent>(); - const VArray<float3> varray = component->attributes()->lookup<float3>("position", - ATTR_DOMAIN_POINT); - varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); - offset += varray.size(); + if (const PointCloudComponent *component = + geometry_set.get_component_for_read<PointCloudComponent>()) { + if (const VArray<float3> varray = component->attributes()->lookup<float3>("position", + ATTR_DOMAIN_POINT)) { + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); + offset += varray.size(); + } } - if (geometry_set.has_curves()) { - const Curves &curves_id = *geometry_set.get_curves_for_read(); - const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + if (const Curves *curves_id = geometry_set.get_curves_for_read()) { + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); Span<float3> array = curves.evaluated_positions(); positions.as_mutable_span().slice(offset, array.size()).copy_from(array); offset += array.size(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index e200350dc18..ab1f8269c39 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -1,16 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BLI_task.hh" - #include "UI_interface.h" #include "UI_resources.h" -#include "DNA_node_types.h" +#include "GEO_fillet_curves.hh" #include "node_geometry_util.hh" -#include "BKE_spline.hh" - namespace blender::nodes::node_geo_curve_fillet_cc { NODE_STORAGE_FUNCS(NodeGeometryCurveFillet) @@ -44,571 +40,18 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__); - data->mode = GEO_NODE_CURVE_FILLET_BEZIER; node->storage = data; } -struct FilletParam { - GeometryNodeCurveFilletMode mode; - - /* Number of points to be added. */ - VArray<int> counts; - - /* Radii for fillet arc at all vertices. */ - VArray<float> radii; - - /* Whether or not fillets are allowed to overlap. */ - bool limit_radius; -}; - -/* A data structure used to store fillet data about all vertices to be filleted. */ -struct FilletData { - Span<float3> positions; - Array<float3> directions, axes; - Array<float> radii, angles; - Array<int> counts; -}; - static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveFillet &storage = node_storage(*node); const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode; - bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next; - nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); } -/* Function to get the center of a fillet. */ -static float3 get_center(const float3 vec_pos2prev, - const float3 pos, - const float3 axis, - const float angle) -{ - float3 vec_pos2center; - rotate_normalized_v3_v3v3fl(vec_pos2center, vec_pos2prev, axis, M_PI_2 - angle / 2.0f); - vec_pos2center *= 1.0f / sinf(angle / 2.0f); - - return vec_pos2center + pos; -} - -/* Function to get the center of the fillet using fillet data */ -static float3 get_center(const float3 vec_pos2prev, const FilletData &fd, const int index) -{ - const float angle = fd.angles[index]; - const float3 axis = fd.axes[index]; - const float3 pos = fd.positions[index]; - - return get_center(vec_pos2prev, pos, axis, angle); -} - -/* Calculate the direction vectors from each vertex to their previous vertex. */ -static Array<float3> calculate_directions(const Span<float3> positions) -{ - const int num = positions.size(); - Array<float3> directions(num); - - for (const int i : IndexRange(num - 1)) { - directions[i] = math::normalize(positions[i + 1] - positions[i]); - } - directions[num - 1] = math::normalize(positions[0] - positions[num - 1]); - - return directions; -} - -/* Calculate the axes around which the fillet is built. */ -static Array<float3> calculate_axes(const Span<float3> directions) -{ - const int num = directions.size(); - Array<float3> axes(num); - - axes[0] = math::normalize(math::cross(-directions[num - 1], directions[0])); - for (const int i : IndexRange(1, num - 1)) { - axes[i] = math::normalize(math::cross(-directions[i - 1], directions[i])); - } - - return axes; -} - -/* Calculate the angle of the arc formed by the fillet. */ -static Array<float> calculate_angles(const Span<float3> directions) -{ - const int num = directions.size(); - Array<float> angles(num); - - angles[0] = M_PI - angle_v3v3(-directions[num - 1], directions[0]); - for (const int i : IndexRange(1, num - 1)) { - angles[i] = M_PI - angle_v3v3(-directions[i - 1], directions[i]); - } - - return angles; -} - -/* Calculate the segment count in each filleted arc. */ -static Array<int> calculate_counts(const FilletParam &fillet_param, - const int num, - const int spline_offset, - const bool cyclic) -{ - Array<int> counts(num, 1); - if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) { - for (const int i : IndexRange(num)) { - counts[i] = fillet_param.counts[spline_offset + i]; - } - } - if (!cyclic) { - counts[0] = counts[num - 1] = 0; - } - - return counts; -} - -/* Calculate the radii for the vertices to be filleted. */ -static Array<float> calculate_radii(const FilletParam &fillet_param, - const int num, - const int spline_offset) -{ - Array<float> radii(num, 0.0f); - if (fillet_param.limit_radius) { - for (const int i : IndexRange(num)) { - radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f); - } - } - else { - for (const int i : IndexRange(num)) { - radii[i] = fillet_param.radii[spline_offset + i]; - } - } - - return radii; -} - -/* Calculate the number of vertices added per vertex on the source spline. */ -static int calculate_point_counts(MutableSpan<int> point_counts, - const Span<float> radii, - const Span<int> counts) -{ - int added_count = 0; - for (const int i : IndexRange(point_counts.size())) { - /* Calculate number of points to be added for the vertex. */ - if (radii[i] != 0.0f) { - added_count += counts[i]; - point_counts[i] = counts[i] + 1; - } - } - - return added_count; -} - -static FilletData calculate_fillet_data(const Spline &spline, - const FilletParam &fillet_param, - int &added_count, - MutableSpan<int> point_counts, - const int spline_offset) -{ - const int num = spline.size(); - - FilletData fd; - fd.directions = calculate_directions(spline.positions()); - fd.positions = spline.positions(); - fd.axes = calculate_axes(fd.directions); - fd.angles = calculate_angles(fd.directions); - fd.counts = calculate_counts(fillet_param, num, spline_offset, spline.is_cyclic()); - fd.radii = calculate_radii(fillet_param, num, spline_offset); - - added_count = calculate_point_counts(point_counts, fd.radii, fd.counts); - - return fd; -} - -/* Limit the radius based on angle and radii to prevent overlapping. */ -static void limit_radii(FilletData &fd, const bool cyclic) -{ - MutableSpan<float> radii(fd.radii); - Span<float> angles(fd.angles); - Span<float3> positions(fd.positions); - - const int num = radii.size(); - const int fillet_count = cyclic ? num : num - 2; - const int start = cyclic ? 0 : 1; - Array<float> max_radii(num, FLT_MAX); - - if (cyclic) { - /* Calculate lengths between adjacent control points. */ - const float len_prev = math::distance(positions[0], positions[num - 1]); - const float len_next = math::distance(positions[0], positions[1]); - - /* Calculate tangent lengths of fillets in control points. */ - const float tan_len = radii[0] * tan(angles[0] / 2.0f); - const float tan_len_prev = radii[num - 1] * tan(angles[num - 1] / 2.0f); - const float tan_len_next = radii[1] * tan(angles[1] / 2.0f); - - float factor_prev = 1.0f, factor_next = 1.0f; - if (tan_len + tan_len_prev > len_prev) { - factor_prev = len_prev / (tan_len + tan_len_prev); - } - if (tan_len + tan_len_next > len_next) { - factor_next = len_next / (tan_len + tan_len_next); - } - - /* Scale max radii by calculated factors. */ - max_radii[0] = radii[0] * std::min(factor_next, factor_prev); - max_radii[1] = radii[1] * factor_next; - max_radii[num - 1] = radii[num - 1] * factor_prev; - } - - /* Initialize max_radii to largest possible radii. */ - float prev_dist = math::distance(positions[1], positions[0]); - for (const int i : IndexRange(1, num - 2)) { - const float temp_dist = math::distance(positions[i], positions[i + 1]); - max_radii[i] = std::min(prev_dist, temp_dist) / tan(angles[i] / 2.0f); - prev_dist = temp_dist; - } - - /* Max radii calculations for each index. */ - for (const int i : IndexRange(start, fillet_count - 1)) { - const float len_next = math::distance(positions[i], positions[i + 1]); - const float tan_len = radii[i] * tan(angles[i] / 2.0f); - const float tan_len_next = radii[i + 1] * tan(angles[i + 1] / 2.0f); - - /* Scale down radii if too large for segment. */ - float factor = 1.0f; - if (tan_len + tan_len_next > len_next) { - factor = len_next / (tan_len + tan_len_next); - } - max_radii[i] = std::min(max_radii[i], radii[i] * factor); - max_radii[i + 1] = std::min(max_radii[i + 1], radii[i + 1] * factor); - } - - /* Assign the max_radii to the fillet data's radii. */ - for (const int i : IndexRange(num)) { - radii[i] = std::min(radii[i], max_radii[i]); - } -} - -/* - * Create a mapping from each vertex in the destination spline to that of the source spline. - * Used for copying the data from the source spline. - */ -static Array<int> create_dst_to_src_map(const Span<int> point_counts, const int total_points) -{ - Array<int> map(total_points); - MutableSpan<int> map_span{map}; - int index = 0; - - for (const int i : point_counts.index_range()) { - map_span.slice(index, point_counts[i]).fill(i); - index += point_counts[i]; - } - - BLI_assert(index == total_points); - - return map; -} - -template<typename T> -static void copy_attribute_by_mapping(const Span<T> src, - MutableSpan<T> dst, - const Span<int> mapping) -{ - for (const int i : dst.index_range()) { - dst[i] = src[mapping[i]]; - } -} - -/* Copy radii and tilts from source spline to destination. Positions are handled later in update - * positions methods. */ -static void copy_common_attributes_by_mapping(const Spline &src, - Spline &dst, - const Span<int> mapping) -{ - copy_attribute_by_mapping(src.radii(), dst.radii(), mapping); - copy_attribute_by_mapping(src.tilts(), dst.tilts(), mapping); - - src.attributes.foreach_attribute( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id); - if (dst.attributes.create(attribute_id, meta_data.data_type)) { - std::optional<GMutableSpan> dst_attribute = dst.attributes.get_for_write(attribute_id); - if (dst_attribute) { - attribute_math::convert_to_static_type(dst_attribute->type(), [&](auto dummy) { - using T = decltype(dummy); - copy_attribute_by_mapping( - src_attribute->typed<T>(), dst_attribute->typed<T>(), mapping); - }); - return true; - } - } - BLI_assert_unreachable(); - return false; - }, - ATTR_DOMAIN_POINT); -} - -/* Update the vertex positions and handle positions of a Bezier spline based on fillet data. */ -static void update_bezier_positions(const FilletData &fd, - BezierSpline &dst_spline, - const BezierSpline &src_spline, - const Span<int> point_counts) -{ - Span<float> radii(fd.radii); - Span<float> angles(fd.angles); - Span<float3> axes(fd.axes); - Span<float3> positions(fd.positions); - Span<float3> directions(fd.directions); - - const int num = radii.size(); - - int i_dst = 0; - for (const int i_src : IndexRange(num)) { - const int count = point_counts[i_src]; - - /* Skip if the point count for the vertex is 1. */ - if (count == 1) { - dst_spline.positions()[i_dst] = src_spline.positions()[i_src]; - dst_spline.handle_types_left()[i_dst] = src_spline.handle_types_left()[i_src]; - dst_spline.handle_types_right()[i_dst] = src_spline.handle_types_right()[i_src]; - dst_spline.handle_positions_left()[i_dst] = src_spline.handle_positions_left()[i_src]; - dst_spline.handle_positions_right()[i_dst] = src_spline.handle_positions_right()[i_src]; - i_dst++; - continue; - } - - /* Calculate the angle to be formed between any 2 adjacent vertices within the fillet. */ - const float segment_angle = angles[i_src] / (count - 1); - /* Calculate the handle length for each added vertex. Equation: L = 4R/3 * tan(A/4) */ - const float handle_length = 4.0f * radii[i_src] / 3.0f * tan(segment_angle / 4.0f); - /* Calculate the distance by which each vertex should be displaced from their initial position. - */ - const float displacement = radii[i_src] * tan(angles[i_src] / 2.0f); - - /* Position the end points of the arc and their handles. */ - const int end_i = i_dst + count - 1; - const float3 prev_dir = i_src == 0 ? -directions[num - 1] : -directions[i_src - 1]; - const float3 next_dir = directions[i_src]; - dst_spline.positions()[i_dst] = positions[i_src] + displacement * prev_dir; - dst_spline.positions()[end_i] = positions[i_src] + displacement * next_dir; - dst_spline.handle_positions_right()[i_dst] = dst_spline.positions()[i_dst] - - handle_length * prev_dir; - dst_spline.handle_positions_left()[end_i] = dst_spline.positions()[end_i] - - handle_length * next_dir; - dst_spline.handle_types_right()[i_dst] = dst_spline.handle_types_left()[end_i] = - BEZIER_HANDLE_ALIGN; - dst_spline.handle_types_left()[i_dst] = dst_spline.handle_types_right()[end_i] = - BEZIER_HANDLE_VECTOR; - dst_spline.mark_cache_invalid(); - - /* Calculate the center of the radius to be formed. */ - const float3 center = get_center(dst_spline.positions()[i_dst] - positions[i_src], fd, i_src); - /* Calculate the vector of the radius formed by the first vertex. */ - float3 radius_vec = dst_spline.positions()[i_dst] - center; - float radius; - radius_vec = math::normalize_and_get_length(radius_vec, radius); - - dst_spline.handle_types_right().slice(1, count - 2).fill(BEZIER_HANDLE_ALIGN); - dst_spline.handle_types_left().slice(1, count - 2).fill(BEZIER_HANDLE_ALIGN); - - /* For each of the vertices in between the end points. */ - for (const int j : IndexRange(1, count - 2)) { - int index = i_dst + j; - /* Rotate the radius by the segment angle and determine its tangent (used for getting handle - * directions). */ - float3 new_radius_vec, tangent_vec; - rotate_normalized_v3_v3v3fl(new_radius_vec, radius_vec, -axes[i_src], segment_angle); - rotate_normalized_v3_v3v3fl(tangent_vec, new_radius_vec, axes[i_src], M_PI_2); - radius_vec = new_radius_vec; - tangent_vec *= handle_length; - - /* Adjust the positions of the respective vertex and its handles. */ - dst_spline.positions()[index] = center + new_radius_vec * radius; - dst_spline.handle_positions_left()[index] = dst_spline.positions()[index] + tangent_vec; - dst_spline.handle_positions_right()[index] = dst_spline.positions()[index] - tangent_vec; - } - - i_dst += count; - } -} - -/* Update the vertex positions of a Poly spline based on fillet data. */ -static void update_poly_positions(const FilletData &fd, - Spline &dst_spline, - const Spline &src_spline, - const Span<int> point_counts) -{ - Span<float> radii(fd.radii); - Span<float> angles(fd.angles); - Span<float3> axes(fd.axes); - Span<float3> positions(fd.positions); - Span<float3> directions(fd.directions); - - const int num = radii.size(); - - int i_dst = 0; - for (const int i_src : IndexRange(num)) { - const int count = point_counts[i_src]; - - /* Skip if the point count for the vertex is 1. */ - if (count == 1) { - dst_spline.positions()[i_dst] = src_spline.positions()[i_src]; - i_dst++; - continue; - } - - const float segment_angle = angles[i_src] / (count - 1); - const float displacement = radii[i_src] * tan(angles[i_src] / 2.0f); - - /* Position the end points of the arc. */ - const int end_i = i_dst + count - 1; - const float3 prev_dir = i_src == 0 ? -directions[num - 1] : -directions[i_src - 1]; - const float3 next_dir = directions[i_src]; - dst_spline.positions()[i_dst] = positions[i_src] + displacement * prev_dir; - dst_spline.positions()[end_i] = positions[i_src] + displacement * next_dir; - - /* Calculate the center of the radius to be formed. */ - const float3 center = get_center(dst_spline.positions()[i_dst] - positions[i_src], fd, i_src); - /* Calculate the vector of the radius formed by the first vertex. */ - float3 radius_vec = dst_spline.positions()[i_dst] - center; - - for (const int j : IndexRange(1, count - 2)) { - /* Rotate the radius by the segment angle */ - float3 new_radius_vec; - rotate_normalized_v3_v3v3fl(new_radius_vec, radius_vec, -axes[i_src], segment_angle); - radius_vec = new_radius_vec; - - dst_spline.positions()[i_dst + j] = center + new_radius_vec; - } - - i_dst += count; - } -} - -static SplinePtr fillet_spline(const Spline &spline, - const FilletParam &fillet_param, - const int spline_offset) -{ - const int num = spline.size(); - const bool cyclic = spline.is_cyclic(); - - if (num < 3) { - return spline.copy(); - } - - /* Initialize the point_counts with 1s (at least one vertex on dst for each vertex on src). */ - Array<int> point_counts(num, 1); - - int added_count = 0; - /* Update point_counts array and added_count. */ - FilletData fd = calculate_fillet_data( - spline, fillet_param, added_count, point_counts, spline_offset); - if (fillet_param.limit_radius) { - limit_radii(fd, cyclic); - } - - const int total_points = added_count + num; - const Array<int> dst_to_src = create_dst_to_src_map(point_counts, total_points); - SplinePtr dst_spline_ptr = spline.copy_only_settings(); - (*dst_spline_ptr).resize(total_points); - copy_common_attributes_by_mapping(spline, *dst_spline_ptr, dst_to_src); - - switch (spline.type()) { - case CURVE_TYPE_BEZIER: { - const BezierSpline &src_spline = static_cast<const BezierSpline &>(spline); - BezierSpline &dst_spline = static_cast<BezierSpline &>(*dst_spline_ptr); - if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) { - dst_spline.handle_types_left().fill(BEZIER_HANDLE_VECTOR); - dst_spline.handle_types_right().fill(BEZIER_HANDLE_VECTOR); - update_poly_positions(fd, dst_spline, src_spline, point_counts); - } - else { - update_bezier_positions(fd, dst_spline, src_spline, point_counts); - } - break; - } - case CURVE_TYPE_POLY: { - update_poly_positions(fd, *dst_spline_ptr, spline, point_counts); - break; - } - case CURVE_TYPE_NURBS: { - const NURBSpline &src_spline = static_cast<const NURBSpline &>(spline); - NURBSpline &dst_spline = static_cast<NURBSpline &>(*dst_spline_ptr); - copy_attribute_by_mapping(src_spline.weights(), dst_spline.weights(), dst_to_src); - update_poly_positions(fd, dst_spline, src_spline, point_counts); - break; - } - case CURVE_TYPE_CATMULL_ROM: { - BLI_assert_unreachable(); - break; - } - } - - return dst_spline_ptr; -} - -static std::unique_ptr<CurveEval> fillet_curve(const CurveEval &input_curve, - const FilletParam &fillet_param) -{ - Span<SplinePtr> input_splines = input_curve.splines(); - - std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>(); - const int splines_num = input_splines.size(); - output_curve->resize(splines_num); - MutableSpan<SplinePtr> output_splines = output_curve->splines(); - Array<int> spline_offsets = input_curve.control_point_offsets(); - - threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - output_splines[i] = fillet_spline(*input_splines[i], fillet_param, spline_offsets[i]); - } - }); - output_curve->attributes = input_curve.attributes; - - return output_curve; -} - -static void calculate_curve_fillet(GeometrySet &geometry_set, - const GeometryNodeCurveFilletMode mode, - const Field<float> &radius_field, - const std::optional<Field<int>> &count_field, - const bool limit_radius) -{ - if (!geometry_set.has_curves()) { - return; - } - - FilletParam fillet_param; - fillet_param.mode = mode; - - CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>(); - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); - fn::FieldEvaluator field_evaluator{field_context, domain_size}; - - field_evaluator.add(radius_field); - - if (mode == GEO_NODE_CURVE_FILLET_POLY) { - field_evaluator.add(*count_field); - } - - field_evaluator.evaluate(); - - fillet_param.radii = field_evaluator.get_evaluated<float>(0); - if (fillet_param.radii.is_single() && fillet_param.radii.get_internal_single() < 0.0f) { - return; - } - - if (mode == GEO_NODE_CURVE_FILLET_POLY) { - fillet_param.counts = field_evaluator.get_evaluated<int>(1); - } - - fillet_param.limit_radius = limit_radius; - - const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component.get_for_read()); - std::unique_ptr<CurveEval> output_curve = fillet_curve(*input_curve, fillet_param); - - geometry_set.replace_curves(curve_eval_to_curves(*output_curve)); -} - static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -625,7 +68,42 @@ static void node_geo_exec(GeoNodeExecParams params) } geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - calculate_curve_fillet(geometry_set, mode, radius_field, count_field, limit_radius); + if (!geometry_set.has_curves()) { + return; + } + + const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>(); + const Curves &curves_id = *component.get_for_read(); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT}; + fn::FieldEvaluator evaluator{context, curves.points_num()}; + evaluator.add(radius_field); + + switch (mode) { + case GEO_NODE_CURVE_FILLET_BEZIER: { + evaluator.evaluate(); + bke::CurvesGeometry dst_curves = geometry::fillet_curves_bezier( + curves, curves.curves_range(), evaluator.get_evaluated<float>(0), limit_radius); + Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves)); + bke::curves_copy_parameters(curves_id, *dst_curves_id); + geometry_set.replace_curves(dst_curves_id); + break; + } + case GEO_NODE_CURVE_FILLET_POLY: { + evaluator.add(*count_field); + evaluator.evaluate(); + bke::CurvesGeometry dst_curves = geometry::fillet_curves_poly( + curves, + curves.curves_range(), + evaluator.get_evaluated<float>(0), + evaluator.get_evaluated<int>(1), + limit_radius); + Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves)); + bke::curves_copy_parameters(curves_id, *dst_curves_id); + geometry_set.replace_curves(dst_curves_id); + break; + } + } }); params.set_output("Curve", std::move(geometry_set)); 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 78a132064ed..2815dd5b2e8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -65,8 +65,10 @@ static void node_geo_exec(GeoNodeExecParams params) Field<int> count = params.extract_input<Field<int>>("Count"); geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) { - if (!component->is_empty()) { - geometry.replace_curves(geometry::resample_to_count(*component, selection, count)); + if (const Curves *src_curves = component->get_for_read()) { + Curves *dst_curves = geometry::resample_to_count(*component, selection, count); + bke::curves_copy_parameters(*src_curves, *dst_curves); + geometry.replace_curves(dst_curves); } } }); @@ -76,8 +78,10 @@ static void node_geo_exec(GeoNodeExecParams params) Field<float> length = params.extract_input<Field<float>>("Length"); geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) { - if (!component->is_empty()) { - geometry.replace_curves(geometry::resample_to_length(*component, selection, length)); + if (const Curves *src_curves = component->get_for_read()) { + Curves *dst_curves = geometry::resample_to_length(*component, selection, length); + bke::curves_copy_parameters(*src_curves, *dst_curves); + geometry.replace_curves(dst_curves); } } }); @@ -86,8 +90,10 @@ static void node_geo_exec(GeoNodeExecParams params) case GEO_NODE_CURVE_RESAMPLE_EVALUATED: geometry_set.modify_geometry_sets([&](GeometrySet &geometry) { if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) { - if (!component->is_empty()) { - geometry.replace_curves(geometry::resample_to_evaluated(*component, selection)); + if (const Curves *src_curves = component->get_for_read()) { + Curves *dst_curves = geometry::resample_to_evaluated(*component, selection); + bke::curves_copy_parameters(*src_curves, *dst_curves); + geometry.replace_curves(dst_curves); } } }); 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 183c98e9c9f..a92479bc5f1 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 @@ -61,15 +61,18 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - if (geometry::try_curves_conversion_in_place(selection, dst_type, [&]() -> Curves & { - return *geometry_set.get_curves_for_write(); - })) { + if (geometry::try_curves_conversion_in_place( + selection, dst_type, [&]() -> bke::CurvesGeometry & { + return bke::CurvesGeometry::wrap(geometry_set.get_curves_for_write()->geometry); + })) { return; } - Curves *dst_curves = geometry::convert_curves(src_component, src_curves, selection, dst_type); + bke::CurvesGeometry dst_curves = geometry::convert_curves(src_curves, selection, dst_type); - geometry_set.replace_curves(dst_curves); + Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves)); + bke::curves_copy_parameters(src_curves_id, *dst_curves_id); + geometry_set.replace_curves(dst_curves_id); }); params.set_output("Curve", std::move(geometry_set)); 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 864e6289135..bd44adb35a2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -35,11 +35,11 @@ static void node_geo_exec(GeoNodeExecParams params) } const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>(); - const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap( - component.get_for_read()->geometry); + const Curves &src_curves_id = *component.get_for_read(); + const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry); GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - fn::FieldEvaluator evaluator{field_context, curves.points_num()}; + fn::FieldEvaluator evaluator{field_context, src_curves.points_num()}; evaluator.add(cuts_field); evaluator.evaluate(); const VArray<int> cuts = evaluator.get_evaluated<int>(0); @@ -47,9 +47,12 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - Curves *result = geometry::subdivide_curves(component, curves, curves.curves_range(), cuts); + bke::CurvesGeometry dst_curves = geometry::subdivide_curves( + src_curves, src_curves.curves_range(), cuts); - geometry_set.replace_curves(result); + Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves)); + bke::curves_copy_parameters(src_curves_id, *dst_curves_id); + geometry_set.replace_curves(dst_curves_id); }); params.set_output("Curve", geometry_set); } 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 00a79168087..51994cb8a41 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include "BKE_curves.hh" #include "BKE_spline.hh" #include "BLI_task.hh" @@ -515,7 +516,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, const VArray<float> starts = evaluator.get_evaluated<float>(0); const VArray<float> ends = evaluator.get_evaluated<float>(1); - std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*geometry_set.get_curves_for_read()); + const Curves &src_curves_id = *geometry_set.get_curves_for_read(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(src_curves_id); MutableSpan<SplinePtr> splines = curve->splines(); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { @@ -566,7 +568,9 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, } }); - geometry_set.replace_curves(curve_eval_to_curves(*curve)); + Curves *dst_curves_id = curve_eval_to_curves(*curve); + bke::curves_copy_parameters(src_curves_id, *dst_curves_id); + geometry_set.replace_curves(dst_curves_id); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc index ab7ddfa71f1..7f03d025db7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc @@ -136,7 +136,7 @@ static void deform_curves(CurvesGeometry &curves, * * TODO: Figure out if this can be smoothly interpolated across the surface as well. * Currently, this is a source of discontinuity in the deformation, because the vector - * changes intantly from one triangle to the next. */ + * changes instantly from one triangle to the next. */ const float3 tangent_reference_dir_old = rest_pos_1 - rest_pos_0; const float3 tangent_reference_dir_new = pos_1_new - pos_0_new; @@ -218,6 +218,12 @@ static void node_geo_exec(GeoNodeExecParams params) return; } const Curves *self_curves_eval = static_cast<const Curves *>(self_ob_eval->data); + if (self_curves_eval->surface_uv_map == nullptr || self_curves_eval->surface_uv_map[0] == '\0') { + pass_through_input(); + const char *message = TIP_("Surface UV map not defined"); + params.error_message_add(NodeWarningType::Error, message); + return; + } /* Take surface information from self-object. */ Object *surface_ob_eval = self_curves_eval->surface; const StringRefNull uv_map_name = self_curves_eval->surface_uv_map; @@ -229,7 +235,7 @@ static void node_geo_exec(GeoNodeExecParams params) } if (surface_ob_eval == nullptr || surface_ob_eval->type != OB_MESH) { pass_through_input(); - params.error_message_add(NodeWarningType::Error, "Curves not attached to a surface."); + params.error_message_add(NodeWarningType::Error, "Curves not attached to a surface"); return; } Object *surface_ob_orig = DEG_get_original_object(surface_ob_eval); @@ -246,7 +252,7 @@ static void node_geo_exec(GeoNodeExecParams params) false); if (surface_mesh_eval == nullptr) { pass_through_input(); - params.error_message_add(NodeWarningType::Error, "Surface has no mesh."); + params.error_message_add(NodeWarningType::Error, "Surface has no mesh"); return; } @@ -258,15 +264,9 @@ static void node_geo_exec(GeoNodeExecParams params) Curves &curves_id = *curves_geometry.get_curves_for_write(); CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); - if (uv_map_name.is_empty()) { - pass_through_input(); - const char *message = TIP_("Surface UV map not defined."); - params.error_message_add(NodeWarningType::Error, message); - return; - } if (!mesh_attributes_eval.contains(uv_map_name)) { pass_through_input(); - char *message = BLI_sprintfN(TIP_("Evaluated surface missing UV map: %s."), + char *message = BLI_sprintfN(TIP_("Evaluated surface missing UV map: %s"), uv_map_name.c_str()); params.error_message_add(NodeWarningType::Error, message); MEM_freeN(message); @@ -274,8 +274,7 @@ static void node_geo_exec(GeoNodeExecParams params) } if (!mesh_attributes_orig.contains(uv_map_name)) { pass_through_input(); - char *message = BLI_sprintfN(TIP_("Original surface missing UV map: %s."), - uv_map_name.c_str()); + char *message = BLI_sprintfN(TIP_("Original surface missing UV map: %s"), uv_map_name.c_str()); params.error_message_add(NodeWarningType::Error, message); MEM_freeN(message); return; @@ -283,13 +282,13 @@ static void node_geo_exec(GeoNodeExecParams params) if (!mesh_attributes_eval.contains(rest_position_name)) { pass_through_input(); params.error_message_add(NodeWarningType::Error, - TIP_("Evaluated surface missing attribute: rest_position.")); + TIP_("Evaluated surface missing attribute: rest_position")); return; } - if (curves.surface_uv_coords().is_empty()) { + if (curves.surface_uv_coords().is_empty() && curves.curves_num() > 0) { pass_through_input(); params.error_message_add(NodeWarningType::Error, - TIP_("Curves are not attached to any UV map.")); + TIP_("Curves are not attached to any UV map")); return; } const VArraySpan<float2> uv_map_orig = mesh_attributes_orig.lookup<float2>(uv_map_name, @@ -337,7 +336,7 @@ static void node_geo_exec(GeoNodeExecParams params) curves.tag_positions_changed(); if (invalid_uv_count) { - char *message = BLI_sprintfN(TIP_("Invalid surface UVs on %d curves."), + char *message = BLI_sprintfN(TIP_("Invalid surface UVs on %d curves"), invalid_uv_count.load()); params.error_message_add(NodeWarningType::Warning, message); MEM_freeN(message); diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index faf5b7f65fa..44793926bbd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -497,8 +497,17 @@ static void point_distribution_calculate(GeometrySet &geometry_set, } PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size()); - memcpy(pointcloud->co, positions.data(), sizeof(float3) * positions.size()); - uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f); + bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write( + *pointcloud); + bke::SpanAttributeWriter<float3> point_positions = + point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT); + bke::SpanAttributeWriter<float> point_radii = + point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT); + point_positions.span.copy_from(positions); + point_radii.span.fill(0.05f); + point_positions.finish(); + point_radii.finish(); + geometry_set.replace_pointcloud(pointcloud); PointCloudComponent &point_component = diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 41136060ab7..8160bc8d589 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -369,6 +369,7 @@ static void duplicate_curves(GeometrySet &geometry_set, point_offsets.last() = dst_points_num; Curves *new_curves_id = bke::curves_new_nomain(dst_points_num, dst_curves_num); + bke::curves_copy_parameters(curves_id, *new_curves_id); bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry); MutableSpan<int> all_dst_offsets = new_curves.offsets_for_write(); @@ -830,6 +831,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set, }); Curves *new_curves_id = bke::curves_new_nomain(dst_num, dst_num); + bke::curves_copy_parameters(src_curves_id, *new_curves_id); bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry); MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write(); for (const int i : new_curves.curves_range()) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc index 5939ed5334d..59e243db4a2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc @@ -85,12 +85,13 @@ class FieldOnDomain final : public GeometryFieldInput { IndexMask /* mask */) const final { const GeometryComponentFieldContext context{component, src_domain_}; - FieldEvaluator value_evaluator{context, component.attribute_domain_size(src_domain_)}; - value_evaluator.add(src_field_); + const int64_t src_domain_size = component.attribute_domain_size(src_domain_); + GArray values(src_field_.cpp_type(), src_domain_size); + FieldEvaluator value_evaluator{context, src_domain_size}; + value_evaluator.add_with_destination(src_field_, values.as_mutable_span()); value_evaluator.evaluate(); - const GVArray &values = value_evaluator.get_evaluated(0); - - return component.attributes()->adapt_domain(values, src_domain_, domain); + return component.attributes()->adapt_domain( + GVArray::ForGArray(std::move(values)), src_domain_, domain); } }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index edbe6e1593f..f14329c96da 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -22,16 +22,6 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Points")); } -template<typename T> -static void copy_attribute_to_points(const VArray<T> &src, - const IndexMask mask, - MutableSpan<T> dst) -{ - for (const int i : mask.index_range()) { - dst[i] = src[mask[i]]; - } -} - static void convert_instances_to_points(GeometrySet &geometry_set, Field<float3> position_field, Field<float> radius_field, @@ -51,16 +41,24 @@ static void convert_instances_to_points(GeometrySet &geometry_set, if (selection.is_empty()) { return; } + const VArray<float3> &positions = evaluator.get_evaluated<float3>(0); + const VArray<float> radii = evaluator.get_evaluated<float>(1); PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size()); geometry_set.replace_pointcloud(pointcloud); - PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>(); + bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write( + *pointcloud); - const VArray<float3> &positions = evaluator.get_evaluated<float3>(0); - copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint}); - const VArray<float> radii = evaluator.get_evaluated<float>(1); - copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint}); + bke::SpanAttributeWriter<float3> point_positions = + point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT); + bke::SpanAttributeWriter<float> point_radii = + point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT); + + positions.materialize_compressed_to_uninitialized(selection, point_positions.span); + radii.materialize_compressed_to_uninitialized(selection, point_radii.span); + point_positions.finish(); + point_radii.finish(); Map<AttributeIDRef, AttributeKind> attributes_to_propagate; geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES}, @@ -78,14 +76,11 @@ static void convert_instances_to_points(GeometrySet &geometry_set, const GVArray src = instances.attributes()->lookup_or_default( attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type); BLI_assert(src); - GSpanAttributeWriter dst = points.attributes_for_write()->lookup_or_add_for_write_only_span( + GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span( attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type); BLI_assert(dst); - attribute_math::convert_to_static_type(attribute_kind.data_type, [&](auto dummy) { - using T = decltype(dummy); - copy_attribute_to_points(src.typed<T>(), selection, dst.span.typed<T>()); - }); + src.materialize_compressed_to_uninitialized(selection, dst.span.data()); dst.finish(); } } 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 f6ee3d00dee..4a79ec159f4 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 @@ -18,7 +18,8 @@ static void node_geo_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - if (!geometry_set.has_mesh()) { + const Mesh *mesh = geometry_set.get_mesh_for_read(); + if (mesh == nullptr) { geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); return; } @@ -34,7 +35,8 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - geometry_set.replace_curves(geometry::mesh_to_curve_convert(component, selection)); + bke::CurvesGeometry curves = geometry::mesh_to_curve_convert(*mesh, selection); + geometry_set.replace_curves(bke::curves_new_nomain(std::move(curves))); geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES}); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 9cc64d4bc44..74fff8efeee 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -18,14 +18,6 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -template<typename T> -static void copy_attribute_to_vertices(const Span<T> src, const IndexMask mask, MutableSpan<T> dst) -{ - for (const int i : mask.index_range()) { - dst[i] = src[mask[i]]; - } -} - /* One improvement would be to move the attribute arrays directly to the mesh when possible. */ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, Field<bool> &selection_field) @@ -66,12 +58,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, mesh_component.attributes_for_write()->lookup_or_add_for_write_only_span( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - VArray<T> src_typed = src.typed<T>(); - VArraySpan<T> src_typed_span{src_typed}; - copy_attribute_to_vertices(src_typed_span, selection, dst.span.typed<T>()); - }); + src.materialize_compressed_to_uninitialized(selection, dst.span.data()); dst.finish(); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index e95db205920..8e65e73d1e2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -47,21 +47,24 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform) static void translate_pointcloud(PointCloud &pointcloud, const float3 translation) { - CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); - BKE_pointcloud_update_customdata_pointers(&pointcloud); - for (const int i : IndexRange(pointcloud.totpoint)) { - add_v3_v3(pointcloud.co[i], translation); + MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud); + SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>( + "position", ATTR_DOMAIN_POINT); + for (const int i : position.span.index_range()) { + position.span[i] += translation; } + position.finish(); } static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform) { - CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); - BKE_pointcloud_update_customdata_pointers(&pointcloud); - for (const int i : IndexRange(pointcloud.totpoint)) { - float3 &co = *(float3 *)pointcloud.co[i]; - co = transform * co; + MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud); + SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>( + "position", ATTR_DOMAIN_POINT); + for (const int i : position.span.index_range()) { + position.span[i] = transform * position.span[i]; } + position.finish(); } static void translate_instances(InstancesComponent &instances, const float3 translation) diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc index 2ec14ad2d29..03657f3e016 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc @@ -121,7 +121,7 @@ static VArray<float3> construct_uv_gvarray(const MeshComponent &component, GEO_uv_parametrizer_lscm_begin(handle, false, method == GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED); GEO_uv_parametrizer_lscm_solve(handle, nullptr, nullptr); GEO_uv_parametrizer_lscm_end(handle); - GEO_uv_parametrizer_average(handle, true); + GEO_uv_parametrizer_average(handle, true, false, false); GEO_uv_parametrizer_pack(handle, margin, true, true); GEO_uv_parametrizer_flush(handle); GEO_uv_parametrizer_delete(handle); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc index 6495dcfffba..a0579372a15 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc @@ -42,8 +42,7 @@ static void node_declare(NodeDeclarationBuilder &b) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); - b.add_input<decl::Float>(N_("IOR")).default_value(1.55f).min(0.0f).max(1000.0f).subtype( - PROP_FACTOR); + b.add_input<decl::Float>(N_("IOR")).default_value(1.55f).min(0.0f).max(1000.0f); b.add_input<decl::Float>(N_("Offset")) .default_value(2.0f * ((float)M_PI) / 180.0f) .min(-M_PI_2) |