Grease Pencil: Support Bézier and Catmull Rom for interpolation tool
This adds support for `Bézier` and `Catmull Rom` curve types to the interpolation tool. When interpolating between to curves of different types, a priority system is used. The priorities from highest for lowest are in the order `NURB`, `Bézier`, `Catmull Rom` and `Polyline`. The reasoning for this order is that: - `NURBs` can be degree order 5 or greater, were as `Bézier` is only order 4. - `Bézier` can match the form of both `Catmull Rom` and `Polyline`, so should be higher priority. - `Catmull Rom` is continuous. - `Polyline` is the simplest and is not smooth, so it should be last. Note: This does add some simple `NURBs` interpolation, but proper handling is more complicated and will be save for a future PR. Resolves: #141178, #143377, #133948 and #136087 Pull Request: https://projects.blender.org/blender/blender/pulls/145683
This commit is contained in:
committed by
casey-bianco-davis
parent
a426e70bf6
commit
1dd536e24f
@@ -239,8 +239,9 @@ static bool interpolate_attribute_to_curves(const StringRef attribute_id,
|
||||
if (bke::attribute_name_is_anonymous(attribute_id)) {
|
||||
return true;
|
||||
}
|
||||
/* Bezier handles and types are interpolated manually. */
|
||||
if (ELEM(attribute_id, "handle_type_left", "handle_type_right", "handle_left", "handle_right")) {
|
||||
return type_counts[CURVE_TYPE_BEZIER] != 0;
|
||||
return false;
|
||||
}
|
||||
if (ELEM(attribute_id, "nurbs_weight")) {
|
||||
return type_counts[CURVE_TYPE_NURBS] != 0;
|
||||
@@ -397,6 +398,7 @@ static void sample_curve_attribute(const bke::CurvesGeometry &src_curves,
|
||||
const OffsetIndices<int> src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices<int> src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
|
||||
const VArray<int8_t> curve_types = src_curves.curve_types();
|
||||
const VArray<int> resolutions = src_curves.resolution();
|
||||
|
||||
#ifndef NDEBUG
|
||||
const int dst_points_num = dst_data.size();
|
||||
@@ -430,15 +432,428 @@ static void sample_curve_attribute(const bke::CurvesGeometry &src_curves,
|
||||
evaluated_data.reinitialize(src_evaluated_points.size());
|
||||
src_curves.interpolate_to_evaluated(
|
||||
i_src_curve, src.slice(src_points), evaluated_data.as_mutable_span());
|
||||
|
||||
Array<int> dst_sample_indices_eval(dst_points.size());
|
||||
Array<float> dst_sample_factors_eval(dst_points.size());
|
||||
|
||||
if (curve_types[i_src_curve] == CURVE_TYPE_BEZIER) {
|
||||
const Span<int> offsets = src_curves.bezier_evaluated_offsets_for_curve(i_src_curve);
|
||||
|
||||
for (const int i : dst_points.index_range()) {
|
||||
const int dst_i = dst_points[i];
|
||||
const int dst_index = dst_sample_indices[dst_i];
|
||||
const float dst_factor = dst_sample_factors[dst_i];
|
||||
const IndexRange segment_eval = IndexRange::from_begin_end_inclusive(
|
||||
offsets[dst_index], offsets[dst_index + 1]);
|
||||
|
||||
const float segment_parameter = segment_eval.first() +
|
||||
dst_factor * segment_eval.size();
|
||||
|
||||
dst_sample_indices_eval[i] = math::floor(segment_parameter);
|
||||
dst_sample_factors_eval[i] = math::mod(segment_parameter, 1.0f);
|
||||
}
|
||||
}
|
||||
else if (curve_types[i_src_curve] == CURVE_TYPE_NURBS) {
|
||||
const int src_size = src_points.size();
|
||||
const int eval_size = src_evaluated_points.size();
|
||||
|
||||
for (const int i : dst_points.index_range()) {
|
||||
const int dst_i = dst_points[i];
|
||||
const int dst_index = dst_sample_indices[dst_i];
|
||||
const float dst_factor = dst_sample_factors[dst_i];
|
||||
|
||||
const float segment_parameter = (dst_index + dst_factor) * float(eval_size) /
|
||||
float(src_size);
|
||||
|
||||
dst_sample_indices_eval[i] = math::floor(segment_parameter);
|
||||
dst_sample_factors_eval[i] = math::mod(segment_parameter, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const int resolution = resolutions[i_src_curve];
|
||||
|
||||
for (const int i : dst_points.index_range()) {
|
||||
const int dst_i = dst_points[i];
|
||||
const int dst_index = dst_sample_indices[dst_i];
|
||||
const float dst_factor = dst_sample_factors[dst_i];
|
||||
|
||||
const float segment_parameter = (dst_index + dst_factor) * resolution;
|
||||
|
||||
dst_sample_indices_eval[i] = math::floor(segment_parameter);
|
||||
dst_sample_factors_eval[i] = math::mod(segment_parameter, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
length_parameterize::interpolate(evaluated_data.as_span(),
|
||||
dst_sample_indices.slice(dst_points),
|
||||
dst_sample_factors.slice(dst_points),
|
||||
dst_sample_indices_eval,
|
||||
dst_sample_factors_eval,
|
||||
dst.slice(dst_points));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static float4 calculate_catmull_rom_basis_derivative(const float parameter)
|
||||
{
|
||||
const float t = parameter;
|
||||
const float s = 1.0f - parameter;
|
||||
return {
|
||||
s * (3.0f * t - 1.0f),
|
||||
9.0f * t * t - 10.0f * t,
|
||||
10.0f * s - 9.0f * s * s,
|
||||
t * (3.0f * t - 2.0f),
|
||||
};
|
||||
}
|
||||
|
||||
static int4 get_catmull_rom_indices(const int src_index,
|
||||
const int src_index_last,
|
||||
const bool cyclic)
|
||||
{
|
||||
int src_index_a = src_index - 1;
|
||||
int src_index_b = src_index;
|
||||
int src_index_c = src_index + 1;
|
||||
int src_index_d = src_index + 2;
|
||||
|
||||
if (src_index_a == -1) {
|
||||
if (cyclic) {
|
||||
src_index_a = src_index_last;
|
||||
}
|
||||
else {
|
||||
src_index_a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (src_index_c > src_index_last) {
|
||||
if (cyclic) {
|
||||
src_index_c -= src_index_last;
|
||||
}
|
||||
else {
|
||||
src_index_c = src_index_last;
|
||||
}
|
||||
}
|
||||
|
||||
if (src_index_d > src_index_last) {
|
||||
if (cyclic) {
|
||||
src_index_d -= src_index_last;
|
||||
}
|
||||
else {
|
||||
src_index_d = src_index_last;
|
||||
}
|
||||
}
|
||||
|
||||
return int4(src_index_a, src_index_b, src_index_c, src_index_d);
|
||||
}
|
||||
|
||||
static void sample_poly_curve_positions_handles(const bool cyclic,
|
||||
const Span<float3> src_pos,
|
||||
const Span<int> dst_indices,
|
||||
const Span<float> dst_factors,
|
||||
const IndexRange dst_points,
|
||||
const int8_t dst_type,
|
||||
MutableSpan<float3> dst_pos,
|
||||
MutableSpan<float3> dst_left,
|
||||
MutableSpan<float3> dst_right,
|
||||
MutableSpan<int8_t> dst_types_left,
|
||||
MutableSpan<int8_t> dst_types_right)
|
||||
{
|
||||
length_parameterize::interpolate(src_pos, dst_indices, dst_factors, dst_pos);
|
||||
|
||||
if (dst_type == CURVE_TYPE_BEZIER) {
|
||||
dst_types_left.fill(BEZIER_HANDLE_VECTOR);
|
||||
dst_types_right.fill(BEZIER_HANDLE_VECTOR);
|
||||
|
||||
for (const int i : dst_points.index_range()) {
|
||||
const int i_prev = (i - 1 + dst_points.size()) % dst_points.size();
|
||||
const int i_next = (i + 1) % dst_points.size();
|
||||
|
||||
/* Vector handles are one third the length of the edge. */
|
||||
if (cyclic || i != 0) {
|
||||
dst_left[i] = math::interpolate(dst_pos[i], dst_pos[i_prev], 1.0f / 3.0f);
|
||||
}
|
||||
else {
|
||||
dst_left[i] = math::interpolate(dst_pos[i], dst_pos[i_next], -1.0f / 3.0f);
|
||||
}
|
||||
|
||||
if (cyclic || i != dst_points.size() - 1) {
|
||||
dst_right[i] = math::interpolate(dst_pos[i], dst_pos[i_next], 1.0f / 3.0f);
|
||||
}
|
||||
else {
|
||||
dst_right[i] = math::interpolate(dst_pos[i], dst_pos[i_prev], -1.0f / 3.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sample_catmull_rom_curve_positions_handles(const bool cyclic,
|
||||
const IndexRange src_points,
|
||||
const Span<float3> src_pos,
|
||||
const Span<int> dst_indices,
|
||||
const Span<float> dst_factors,
|
||||
const IndexRange dst_points,
|
||||
const int8_t dst_type,
|
||||
MutableSpan<float3> dst_pos,
|
||||
MutableSpan<float3> dst_left,
|
||||
MutableSpan<float3> dst_right,
|
||||
MutableSpan<int8_t> dst_types_left,
|
||||
MutableSpan<int8_t> dst_types_right)
|
||||
{
|
||||
dst_types_left.fill(BEZIER_HANDLE_ALIGN);
|
||||
dst_types_right.fill(BEZIER_HANDLE_ALIGN);
|
||||
|
||||
for (const int i : dst_points.index_range()) {
|
||||
const int src_index = dst_indices[i];
|
||||
const float src_factor = dst_factors[i];
|
||||
|
||||
const int i_prev = (i - 1 + dst_points.size()) % dst_points.size();
|
||||
const float src_factor_prev = dst_factors[i_prev];
|
||||
|
||||
const int i_next = (i + 1) % dst_points.size();
|
||||
const float src_factor_next = dst_factors[i_next];
|
||||
|
||||
const int4 src_indices = get_catmull_rom_indices(src_index, src_points.size() - 1, cyclic);
|
||||
|
||||
const float3 &pos_a = src_pos[src_indices[0]];
|
||||
const float3 &pos_b = src_pos[src_indices[1]];
|
||||
const float3 &pos_c = src_pos[src_indices[2]];
|
||||
const float3 &pos_d = src_pos[src_indices[3]];
|
||||
|
||||
if (src_factor == 0.0f) {
|
||||
dst_pos[i] = src_pos[src_index];
|
||||
|
||||
if (dst_type == CURVE_TYPE_BEZIER) {
|
||||
const float3 derivative = 0.5f * (pos_c - pos_a);
|
||||
dst_right[i] = dst_pos[i] + derivative / 3.0f;
|
||||
dst_left[i] = dst_pos[i] - derivative / 3.0f;
|
||||
|
||||
if ((cyclic || i != 0) && dst_indices[i_prev] == src_index - 1) {
|
||||
dst_left[i] = dst_pos[i] + (dst_left[i] - dst_pos[i]) * (1.0f - src_factor_prev);
|
||||
}
|
||||
if ((cyclic || i != dst_points.size() - 1) && dst_indices[i_next] == src_index) {
|
||||
dst_right[i] = dst_pos[i] + (dst_right[i] - dst_pos[i]) * src_factor_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float4 weights = bke::curves::catmull_rom::calculate_basis(src_factor);
|
||||
|
||||
dst_pos[i] = 0.5f * bke::attribute_math::mix4<float3>(weights, pos_a, pos_b, pos_c, pos_d);
|
||||
if (dst_type == CURVE_TYPE_BEZIER) {
|
||||
const float4 dwdt = calculate_catmull_rom_basis_derivative(src_factor);
|
||||
|
||||
const float3 derivative = 0.5f * bke::attribute_math::mix4<float3>(
|
||||
dwdt, pos_a, pos_b, pos_c, pos_d);
|
||||
|
||||
/* Bezier handles are one third the length the derivative at the control points. */
|
||||
dst_right[i] = dst_pos[i] + derivative / 3.0f;
|
||||
dst_left[i] = dst_pos[i] - derivative / 3.0f;
|
||||
|
||||
if ((cyclic || i != 0) && dst_indices[i_prev] == src_index - 1) {
|
||||
dst_left[i] = dst_pos[i] + (dst_left[i] - dst_pos[i]) * (src_factor - src_factor_prev);
|
||||
}
|
||||
if ((cyclic || i != dst_points.size() - 1) && dst_indices[i_next] == src_index) {
|
||||
dst_right[i] = dst_pos[i] + (dst_right[i] - dst_pos[i]) * (src_factor_next - src_factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sample_bezier_curve_positions_handles(const bool cyclic,
|
||||
const IndexRange src_points,
|
||||
const Span<float3> src_pos,
|
||||
const Span<float3> src_handle_left,
|
||||
const Span<float3> src_handle_right,
|
||||
const VArray<int8_t> src_types_left,
|
||||
const VArray<int8_t> src_types_right,
|
||||
const Span<int> dst_indices,
|
||||
const Span<float> dst_factors,
|
||||
const IndexRange dst_points,
|
||||
MutableSpan<float3> dst_pos,
|
||||
MutableSpan<float3> dst_left,
|
||||
MutableSpan<float3> dst_right,
|
||||
MutableSpan<int8_t> dst_types_left,
|
||||
MutableSpan<int8_t> dst_types_right)
|
||||
{
|
||||
const Span<float3> src_left = src_handle_left.slice(src_points);
|
||||
const Span<float3> src_right = src_handle_right.slice(src_points);
|
||||
|
||||
for (const int i : dst_points.index_range()) {
|
||||
const int src_index = dst_indices[i];
|
||||
const float src_factor = dst_factors[i];
|
||||
|
||||
const int i_prev = (i - 1 + dst_points.size()) % dst_points.size();
|
||||
const float src_factor_prev = dst_factors[i_prev];
|
||||
|
||||
const int i_next = (i + 1) % dst_points.size();
|
||||
const float src_factor_next = dst_factors[i_next];
|
||||
|
||||
if (src_factor == 0.0f) {
|
||||
dst_pos[i] = src_pos[src_index];
|
||||
dst_left[i] = src_left[src_index];
|
||||
dst_right[i] = src_right[src_index];
|
||||
|
||||
if ((cyclic || i != 0) && dst_indices[i_prev] == src_index - 1) {
|
||||
dst_left[i] = dst_pos[i] + (dst_left[i] - dst_pos[i]) * (1.0f - src_factor_prev);
|
||||
}
|
||||
if ((cyclic || i != dst_points.size() - 1) && dst_indices[i_next] == src_index) {
|
||||
dst_right[i] = dst_pos[i] + (dst_right[i] - dst_pos[i]) * src_factor_next;
|
||||
}
|
||||
|
||||
dst_types_left[i] = src_types_left[src_index];
|
||||
dst_types_right[i] = src_types_right[src_index];
|
||||
}
|
||||
else {
|
||||
const int src_index_next = (src_index + 1) % src_pos.size();
|
||||
|
||||
bke::curves::bezier::Insertion insert_point = bke::curves::bezier::insert(
|
||||
src_pos[src_index],
|
||||
src_right[src_index],
|
||||
src_left[src_index_next],
|
||||
src_pos[src_index_next],
|
||||
src_factor);
|
||||
|
||||
dst_pos[i] = insert_point.position;
|
||||
dst_left[i] = insert_point.left_handle;
|
||||
dst_right[i] = insert_point.right_handle;
|
||||
|
||||
if ((cyclic || i != 0) && dst_indices[i_prev] == src_index) {
|
||||
/* The handles already have been scaled by `src_factor`, so we divide to remove. */
|
||||
dst_left[i] = dst_pos[i] +
|
||||
(dst_left[i] - dst_pos[i]) * (src_factor - src_factor_prev) / src_factor;
|
||||
}
|
||||
if ((cyclic || i != dst_points.size() - 1) && dst_indices[i_next] == src_index) {
|
||||
/* The handles already have been scaled by `1.0f - src_factor`, so we divide to remove.
|
||||
*/
|
||||
dst_right[i] = dst_pos[i] + (dst_right[i] - dst_pos[i]) * (src_factor_next - src_factor) /
|
||||
(1.0f - src_factor);
|
||||
}
|
||||
|
||||
/* Output Vector type if the segment is also Vector, otherwise be aligned. */
|
||||
if (src_types_left[src_index] == BEZIER_HANDLE_VECTOR &&
|
||||
src_types_left[src_index_next] == BEZIER_HANDLE_VECTOR)
|
||||
{
|
||||
dst_types_left[i] = BEZIER_HANDLE_VECTOR;
|
||||
dst_types_right[i] = BEZIER_HANDLE_VECTOR;
|
||||
}
|
||||
else {
|
||||
dst_types_left[i] = BEZIER_HANDLE_ALIGN;
|
||||
dst_types_right[i] = BEZIER_HANDLE_ALIGN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resample the positions and handles. */
|
||||
static void sample_curve_positions_and_handles(const bke::CurvesGeometry &src_curves,
|
||||
const Span<int> src_curve_indices,
|
||||
const OffsetIndices<int> dst_points_by_curve,
|
||||
const VArray<int8_t> dst_types,
|
||||
const IndexMask &dst_curve_mask,
|
||||
const Span<int> dst_sample_indices,
|
||||
const Span<float> dst_sample_factors,
|
||||
MutableSpan<float3> dst_positions,
|
||||
MutableSpan<float3> dst_handles_left,
|
||||
MutableSpan<float3> dst_handles_right,
|
||||
MutableSpan<int8_t> dst_handle_types_left,
|
||||
MutableSpan<int8_t> dst_handle_types_right)
|
||||
{
|
||||
const OffsetIndices<int> src_points_by_curve = src_curves.points_by_curve();
|
||||
const VArray<int8_t> src_types = src_curves.curve_types();
|
||||
const Span<float3> src_positions = src_curves.positions();
|
||||
const VArray<bool> src_cyclic = src_curves.cyclic();
|
||||
const std::optional<Span<float3>> src_handle_left = src_curves.handle_positions_left();
|
||||
const std::optional<Span<float3>> src_handle_right = src_curves.handle_positions_right();
|
||||
const VArray<int8_t> src_types_left = src_curves.handle_types_left();
|
||||
const VArray<int8_t> src_types_right = src_curves.handle_types_right();
|
||||
|
||||
#ifndef NDEBUG
|
||||
const int dst_points_num = dst_positions.size();
|
||||
BLI_assert(dst_handles_left.size() == dst_points_num);
|
||||
BLI_assert(dst_handles_right.size() == dst_points_num);
|
||||
BLI_assert(dst_sample_indices.size() == dst_points_num);
|
||||
BLI_assert(dst_sample_factors.size() == dst_points_num);
|
||||
#endif
|
||||
|
||||
dst_curve_mask.foreach_index([&](const int i_dst_curve, const int pos) {
|
||||
const int i_src_curve = src_curve_indices[pos];
|
||||
if (i_src_curve < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool cyclic = src_cyclic[i_src_curve];
|
||||
|
||||
const IndexRange src_points = src_points_by_curve[i_src_curve];
|
||||
const IndexRange dst_points = dst_points_by_curve[i_dst_curve];
|
||||
|
||||
const Span<float3> src_pos = src_positions.slice(src_points);
|
||||
const Span<int> dst_indices = dst_sample_indices.slice(dst_points);
|
||||
const Span<float> dst_factors = dst_sample_factors.slice(dst_points);
|
||||
|
||||
MutableSpan<float3> dst_pos = dst_positions.slice(dst_points);
|
||||
MutableSpan<float3> dst_left = dst_handles_left.slice(dst_points);
|
||||
MutableSpan<float3> dst_right = dst_handles_right.slice(dst_points);
|
||||
MutableSpan<int8_t> dst_types_left = dst_handle_types_left.slice(dst_points);
|
||||
MutableSpan<int8_t> dst_types_right = dst_handle_types_right.slice(dst_points);
|
||||
|
||||
if (src_types[i_src_curve] == CURVE_TYPE_POLY) {
|
||||
sample_poly_curve_positions_handles(cyclic,
|
||||
src_pos,
|
||||
dst_indices,
|
||||
dst_factors,
|
||||
dst_points,
|
||||
dst_types[i_dst_curve],
|
||||
dst_pos,
|
||||
dst_left,
|
||||
dst_right,
|
||||
dst_types_left,
|
||||
dst_types_right);
|
||||
}
|
||||
else if (src_types[i_src_curve] == CURVE_TYPE_NURBS) {
|
||||
/* NURBS take priority over Bézier, so we should never be trying to be Bézier. */
|
||||
BLI_assert(dst_types[i_dst_curve] != CURVE_TYPE_BEZIER);
|
||||
|
||||
length_parameterize::interpolate(src_pos, dst_indices, dst_factors, dst_pos);
|
||||
}
|
||||
else if (src_types[i_src_curve] == CURVE_TYPE_CATMULL_ROM) {
|
||||
sample_catmull_rom_curve_positions_handles(cyclic,
|
||||
src_points,
|
||||
src_pos,
|
||||
dst_indices,
|
||||
dst_factors,
|
||||
dst_points,
|
||||
dst_types[i_dst_curve],
|
||||
dst_pos,
|
||||
dst_left,
|
||||
dst_right,
|
||||
dst_types_left,
|
||||
dst_types_right);
|
||||
}
|
||||
else if (src_types[i_src_curve] == CURVE_TYPE_BEZIER) {
|
||||
BLI_assert(src_handle_left);
|
||||
BLI_assert(src_handle_right);
|
||||
|
||||
sample_bezier_curve_positions_handles(cyclic,
|
||||
src_points,
|
||||
src_pos,
|
||||
*src_handle_left,
|
||||
*src_handle_right,
|
||||
src_types_left,
|
||||
src_types_right,
|
||||
dst_indices,
|
||||
dst_factors,
|
||||
dst_points,
|
||||
dst_pos,
|
||||
dst_left,
|
||||
dst_right,
|
||||
dst_types_left,
|
||||
dst_types_right);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void mix_arrays(const Span<T> from,
|
||||
const Span<T> to,
|
||||
@@ -503,6 +918,79 @@ static void mix_arrays(const GSpan src_from,
|
||||
});
|
||||
}
|
||||
|
||||
static int8_t mix_handle_type(const int8_t from_type, const int8_t to_type)
|
||||
{
|
||||
/* Vector handles can only be mixed with other vector handles, otherwise use free handle as
|
||||
* fallback. */
|
||||
if (from_type == BEZIER_HANDLE_VECTOR && to_type == BEZIER_HANDLE_VECTOR) {
|
||||
return BEZIER_HANDLE_VECTOR;
|
||||
}
|
||||
if (from_type == BEZIER_HANDLE_VECTOR || to_type == BEZIER_HANDLE_VECTOR) {
|
||||
return BEZIER_HANDLE_FREE;
|
||||
}
|
||||
|
||||
if (from_type == BEZIER_HANDLE_FREE || to_type == BEZIER_HANDLE_FREE) {
|
||||
return BEZIER_HANDLE_FREE;
|
||||
}
|
||||
if (from_type == BEZIER_HANDLE_ALIGN || to_type == BEZIER_HANDLE_ALIGN) {
|
||||
return BEZIER_HANDLE_ALIGN;
|
||||
}
|
||||
return BEZIER_HANDLE_AUTO;
|
||||
}
|
||||
|
||||
static void mix_handle_type_arrays(const Span<int8_t> src_from,
|
||||
const Span<int8_t> src_to,
|
||||
const IndexMask &group_selection,
|
||||
const OffsetIndices<int> groups,
|
||||
const MutableSpan<int8_t> dst)
|
||||
{
|
||||
group_selection.foreach_index(GrainSize(32), [&](const int curve) {
|
||||
for (const int i : groups[curve]) {
|
||||
dst[i] = mix_handle_type(src_from[i], src_to[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Calculate the new curve's type by using the type with highest priority. */
|
||||
static void mix_curve_type(const Span<int> from_curve_indices,
|
||||
const Span<int> to_curve_indices,
|
||||
const VArray<int8_t> &from_types,
|
||||
const VArray<int8_t> &to_types,
|
||||
const IndexMask &dst_curve_mask,
|
||||
MutableSpan<int8_t> dst_curve_types)
|
||||
{
|
||||
dst_curve_mask.foreach_index([&](const int i_dst_curve, const int pos) {
|
||||
const int i_from_curve = from_curve_indices[pos];
|
||||
const int i_to_curve = to_curve_indices[pos];
|
||||
|
||||
if (i_from_curve < 0) {
|
||||
dst_curve_types[i_dst_curve] = to_types[i_to_curve];
|
||||
return;
|
||||
}
|
||||
if (i_to_curve < 0) {
|
||||
dst_curve_types[i_dst_curve] = from_types[i_from_curve];
|
||||
return;
|
||||
}
|
||||
|
||||
const int8_t from_type = from_types[i_from_curve];
|
||||
const int8_t to_type = to_types[i_to_curve];
|
||||
|
||||
if (from_type == CURVE_TYPE_NURBS || to_type == CURVE_TYPE_NURBS) {
|
||||
dst_curve_types[i_dst_curve] = CURVE_TYPE_NURBS;
|
||||
return;
|
||||
}
|
||||
if (from_type == CURVE_TYPE_BEZIER || to_type == CURVE_TYPE_BEZIER) {
|
||||
dst_curve_types[i_dst_curve] = CURVE_TYPE_BEZIER;
|
||||
return;
|
||||
}
|
||||
if (from_type == CURVE_TYPE_CATMULL_ROM || to_type == CURVE_TYPE_CATMULL_ROM) {
|
||||
dst_curve_types[i_dst_curve] = CURVE_TYPE_CATMULL_ROM;
|
||||
return;
|
||||
}
|
||||
dst_curve_types[i_dst_curve] = CURVE_TYPE_POLY;
|
||||
});
|
||||
}
|
||||
|
||||
void interpolate_curves_with_samples(const CurvesGeometry &from_curves,
|
||||
const CurvesGeometry &to_curves,
|
||||
const Span<int> from_curve_indices,
|
||||
@@ -527,13 +1015,23 @@ void interpolate_curves_with_samples(const CurvesGeometry &from_curves,
|
||||
return;
|
||||
}
|
||||
|
||||
const Span<float3> from_evaluated_positions = from_curves.evaluated_positions();
|
||||
const Span<float3> to_evaluated_positions = to_curves.evaluated_positions();
|
||||
from_curves.ensure_can_interpolate_to_evaluated();
|
||||
to_curves.ensure_can_interpolate_to_evaluated();
|
||||
|
||||
/* All resampled curves are poly curves. */
|
||||
dst_curves.fill_curve_types(dst_curve_mask, CURVE_TYPE_POLY);
|
||||
mix_curve_type(from_curve_indices,
|
||||
to_curve_indices,
|
||||
from_curves.curve_types(),
|
||||
to_curves.curve_types(),
|
||||
dst_curve_mask,
|
||||
dst_curves.curve_types_for_write());
|
||||
|
||||
dst_curves.update_curve_types();
|
||||
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
MutableSpan<float3> dst_left = dst_curves.handle_positions_left_for_write();
|
||||
MutableSpan<float3> dst_right = dst_curves.handle_positions_right_for_write();
|
||||
MutableSpan<int8_t> dst_types_left = dst_curves.handle_types_left_for_write();
|
||||
MutableSpan<int8_t> dst_types_right = dst_curves.handle_types_right_for_write();
|
||||
|
||||
AttributesForInterpolation point_attributes = gather_point_attributes_to_interpolate(
|
||||
from_curves, to_curves, dst_curves);
|
||||
@@ -634,33 +1132,77 @@ void interpolate_curves_with_samples(const CurvesGeometry &from_curves,
|
||||
}
|
||||
|
||||
{
|
||||
Array<float3> from_samples(dst_positions.size());
|
||||
Array<float3> to_samples(dst_positions.size());
|
||||
const VArray<int8_t> dst_types = dst_curves.curve_types();
|
||||
|
||||
/* Interpolate the evaluated positions to the resampled curves. */
|
||||
sample_curve_attribute(from_curves,
|
||||
from_curve_indices,
|
||||
dst_points_by_curve,
|
||||
from_evaluated_positions,
|
||||
dst_curve_mask,
|
||||
from_sample_indices,
|
||||
from_sample_factors,
|
||||
from_samples.as_mutable_span());
|
||||
sample_curve_attribute(to_curves,
|
||||
to_curve_indices,
|
||||
dst_points_by_curve,
|
||||
to_evaluated_positions,
|
||||
dst_curve_mask,
|
||||
to_sample_indices,
|
||||
to_sample_factors,
|
||||
to_samples.as_mutable_span());
|
||||
Array<float3> from_pos(dst_positions.size());
|
||||
Array<float3> to_pos(dst_positions.size());
|
||||
Array<float3> from_left(dst_left.size());
|
||||
Array<float3> to_left(dst_left.size());
|
||||
Array<float3> from_right(dst_right.size());
|
||||
Array<float3> to_right(dst_right.size());
|
||||
|
||||
mix_arrays(from_samples.as_span(),
|
||||
to_samples.as_span(),
|
||||
Array<int8_t> from_types_left(dst_left.size());
|
||||
Array<int8_t> to_types_left(dst_left.size());
|
||||
Array<int8_t> from_types_right(dst_right.size());
|
||||
Array<int8_t> to_types_right(dst_right.size());
|
||||
|
||||
/* Interpolate the positions and handles to the resampled curves. */
|
||||
sample_curve_positions_and_handles(from_curves,
|
||||
from_curve_indices,
|
||||
dst_points_by_curve,
|
||||
dst_types,
|
||||
dst_curve_mask,
|
||||
from_sample_indices,
|
||||
from_sample_factors,
|
||||
from_pos.as_mutable_span(),
|
||||
from_left.as_mutable_span(),
|
||||
from_right.as_mutable_span(),
|
||||
from_types_left.as_mutable_span(),
|
||||
from_types_right.as_mutable_span());
|
||||
sample_curve_positions_and_handles(to_curves,
|
||||
to_curve_indices,
|
||||
dst_points_by_curve,
|
||||
dst_types,
|
||||
dst_curve_mask,
|
||||
to_sample_indices,
|
||||
to_sample_factors,
|
||||
to_pos.as_mutable_span(),
|
||||
to_left.as_mutable_span(),
|
||||
to_right.as_mutable_span(),
|
||||
to_types_left.as_mutable_span(),
|
||||
to_types_right.as_mutable_span());
|
||||
|
||||
mix_arrays(from_pos.as_span(),
|
||||
to_pos.as_span(),
|
||||
mix_factors,
|
||||
dst_curve_mask,
|
||||
dst_points_by_curve,
|
||||
dst_positions);
|
||||
mix_arrays(from_left.as_span(),
|
||||
to_left.as_span(),
|
||||
mix_factors,
|
||||
dst_curve_mask,
|
||||
dst_points_by_curve,
|
||||
dst_left);
|
||||
mix_arrays(from_right.as_span(),
|
||||
to_right.as_span(),
|
||||
mix_factors,
|
||||
dst_curve_mask,
|
||||
dst_points_by_curve,
|
||||
dst_right);
|
||||
|
||||
mix_handle_type_arrays(from_types_left.as_span(),
|
||||
to_types_left.as_span(),
|
||||
dst_curve_mask,
|
||||
dst_points_by_curve,
|
||||
dst_types_left);
|
||||
mix_handle_type_arrays(from_types_right.as_span(),
|
||||
to_types_right.as_span(),
|
||||
dst_curve_mask,
|
||||
dst_points_by_curve,
|
||||
dst_types_right);
|
||||
|
||||
dst_curves.calculate_bezier_auto_handles();
|
||||
}
|
||||
|
||||
for (const int i_attribute : curve_attributes.dst.index_range()) {
|
||||
@@ -705,6 +1247,8 @@ void interpolate_curves_with_samples(const CurvesGeometry &from_curves,
|
||||
for (bke::GSpanAttributeWriter &attribute : curve_attributes.dst) {
|
||||
attribute.finish();
|
||||
}
|
||||
|
||||
dst_curves.tag_topology_changed();
|
||||
}
|
||||
|
||||
static void sample_curve_uniform(const bke::CurvesGeometry &curves,
|
||||
|
||||
Reference in New Issue
Block a user