Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-04-09 20:46:30 +0300
committerHans Goudey <h.goudey@me.com>2022-04-09 20:46:30 +0300
commitceed37fc5cbb466a04b4b4f7afba5dcd561fdd6a (patch)
tree83f515a54846d868d57a10f14854df69cf4c82fd /source/blender/blenkernel/intern/geometry_component_curves.cc
parent69a4d113e8dd3f2f267536b2b93af2540f3a0978 (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.cc131
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,