diff options
author | Hans Goudey <h.goudey@me.com> | 2022-04-09 20:46:30 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-04-09 20:46:30 +0300 |
commit | ceed37fc5cbb466a04b4b4f7afba5dcd561fdd6a (patch) | |
tree | 83f515a54846d868d57a10f14854df69cf4c82fd /source/blender/blenkernel/intern/geometry_component_curves.cc | |
parent | 69a4d113e8dd3f2f267536b2b93af2540f3a0978 (diff) |
Curves: Port tangent and normal calculation to the new data-block
Port the "Normal" and "Curve Tangent" nodes to the new curves data-block
to avoid the conversion to `CurveEval`. This should make them faster by
avoiding all that copying, but otherwise nothing else has changed.
This also includes a fix to move the normal mode as a built-in curve
attribute when converting to and from `CurveEval`. The attribute is
needed because the option is used implicitly in many nodes currently.
Differential Revision: https://developer.blender.org/D14609
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_component_curves.cc')
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_curves.cc | 131 |
1 files changed, 80 insertions, 51 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index de986fec951..0bcab0aae7a 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -141,81 +141,97 @@ const Curve *CurveComponent::get_curve_for_render() const namespace blender::bke { -static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals) +static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves) { - Span<int> offsets = spline.control_point_offsets(); - Span<float3> evaluated_normals = spline.evaluated_normals(); - for (const int i : IndexRange(spline.size())) { - normals[i] = evaluated_normals[offsets[i]]; - } -} + const VArray<int8_t> types = curves.curve_types(); + const VArray<int> resolutions = curves.resolution(); + const VArray<bool> curves_cyclic = curves.cyclic(); -static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals) -{ - normals.copy_from(spline.evaluated_normals()); -} + const Span<float3> positions = curves.positions(); + const VArray<int8_t> normal_modes = curves.normal_mode(); -/** - * Because NURBS control points are not necessarily on the path, the normal at the control points - * is not well defined, so create a temporary poly spline to find the normals. This requires extra - * copying currently, but may be more efficient in the future if attributes have some form of CoW. - */ -static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals) -{ - PolySpline poly_spline; - poly_spline.resize(spline.size()); - poly_spline.positions().copy_from(spline.positions()); - poly_spline.tilts().copy_from(spline.tilts()); - normals.copy_from(poly_spline.evaluated_normals()); -} + const Span<float3> evaluated_normals = curves.evaluated_normals(); -static Array<float3> curve_normal_point_domain(const CurveEval &curve) -{ - Span<SplinePtr> splines = curve.splines(); - Array<int> offsets = curve.control_point_offsets(); - const int total_size = offsets.last(); - Array<float3> normals(total_size); - - threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - const Spline &spline = *splines[i]; - MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())}; - switch (splines[i]->type()) { - case CURVE_TYPE_BEZIER: - calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals); + Array<float3> results(curves.points_num()); + + threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) { + Vector<float3> nurbs_tangents; + + for (const int i_curve : range) { + const IndexRange points = curves.points_for_curve(i_curve); + const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve); + + MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points); + + switch (types[i_curve]) { + case CURVE_TYPE_CATMULL_ROM: { + const Span<float3> normals = evaluated_normals.slice(evaluated_points); + const int resolution = resolutions[i_curve]; + for (const int i : IndexRange(points.size())) { + curve_normals[i] = normals[resolution * i]; + } break; + } case CURVE_TYPE_POLY: - calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals); + curve_normals.copy_from(evaluated_normals.slice(evaluated_points)); break; - case CURVE_TYPE_NURBS: - calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals); + case CURVE_TYPE_BEZIER: { + const Span<float3> normals = evaluated_normals.slice(evaluated_points); + curve_normals.first() = normals.first(); + const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve); + for (const int i : IndexRange(points.size()).drop_front(1)) { + curve_normals[i] = normals[offsets[i - 1]]; + } break; - case CURVE_TYPE_CATMULL_ROM: - BLI_assert_unreachable(); + } + case CURVE_TYPE_NURBS: { + /* For NURBS curves there is no obvious correspondence between specific evaluated points + * and control points, so normals are determined by treating them as poly curves. */ + nurbs_tangents.clear(); + nurbs_tangents.resize(points.size()); + const bool cyclic = curves_cyclic[i_curve]; + const Span<float3> curve_positions = positions.slice(points); + bke::curves::poly::calculate_tangents(curve_positions, cyclic, nurbs_tangents); + switch (NormalMode(normal_modes[i_curve])) { + case NORMAL_MODE_Z_UP: + bke::curves::poly::calculate_normals_z_up(nurbs_tangents, curve_normals); + break; + case NORMAL_MODE_MINIMUM_TWIST: + bke::curves::poly::calculate_normals_minimum(nurbs_tangents, cyclic, curve_normals); + break; + } break; + } } } }); - return normals; + return results; } VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain) { - if (component.is_empty()) { - return nullptr; + if (!component.has_curves()) { + return {}; + } + + const Curves &curves_id = *component.get_for_read(); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); + + const VArray<int8_t> types = curves.curve_types(); + if (curves.is_single_type(CURVE_TYPE_POLY)) { + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain); } - const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); + + Array<float3> normals = curve_normal_point_domain(curves); if (domain == ATTR_DOMAIN_POINT) { - Array<float3> normals = curve_normal_point_domain(*curve); return VArray<float3>::ForContainer(std::move(normals)); } if (domain == ATTR_DOMAIN_CURVE) { - Array<float3> point_normals = curve_normal_point_domain(*curve); - VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); return component.attribute_try_adapt_domain<float3>( - std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } return nullptr; @@ -456,6 +472,18 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() make_array_write_attribute<int>, tag_component_topology_changed); + static BuiltinCustomDataLayerProvider normal_mode("normal_mode", + ATTR_DOMAIN_CURVE, + CD_PROP_INT8, + CD_PROP_INT8, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + curve_access, + make_array_read_attribute<int8_t>, + make_array_write_attribute<int8_t>, + tag_component_normals_changed); + static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode", ATTR_DOMAIN_CURVE, CD_PROP_INT8, @@ -515,6 +543,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() &handle_left, &handle_type_right, &handle_type_left, + &normal_mode, &nurbs_order, &nurbs_weight, &curve_type, |