171 Vector<float3> nurbs_tangents;
173 for (const int i_curve : range) {
174 const IndexRange points = points_by_curve[i_curve];
175 const IndexRange evaluated_points = evaluated_points_by_curve[i_curve];
177 MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points);
179 switch (types[i_curve]) {
180 case CURVE_TYPE_CATMULL_ROM: {
181 const Span<float3> normals = evaluated_normals.slice(evaluated_points);
182 const int resolution = resolutions[i_curve];
183 for (const int i : IndexRange(points.size())) {
184 curve_normals[i] = normals[resolution * i];
188 case CURVE_TYPE_POLY:
189 curve_normals.copy_from(evaluated_normals.slice(evaluated_points));
191 case CURVE_TYPE_BEZIER: {
192 const Span<float3> normals = evaluated_normals.slice(evaluated_points);
193 curve_normals.first() = normals.first();
194 const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
195 for (const int i : IndexRange(points.size()).drop_front(1)) {
196 curve_normals[i] = normals[offsets[i]];
200 case CURVE_TYPE_NURBS: {
203 nurbs_tangents.clear();
204 nurbs_tangents.resize(points.size());
205 const bool cyclic = curves_cyclic[i_curve];
206 const Span<float3> curve_positions = positions.slice(points);
207 curves::poly::calculate_tangents(curve_positions, cyclic, nurbs_tangents);
208 switch (NormalMode(normal_modes[i_curve])) {
209 case NORMAL_MODE_Z_UP:
210 curves::poly::calculate_normals_z_up(nurbs_tangents, curve_normals);
212 case NORMAL_MODE_MINIMUM_TWIST:
213 curves::poly::calculate_normals_minimum(nurbs_tangents, cyclic, curve_normals);
215 case NORMAL_MODE_FREE:
216 custom_normals.materialize(points, results);