Fix #120698: GPv3: Don't move the first stroke point
There are two ways the first stroke point is moved after initial placement: - The `process_extension_sample` overwrites the initial values of the sample point after `process_start_sample`. It copies the _new_ sample position, until a threshold (3 pixels) is reached and the 2nd point is created, and the 1st point remains stationary. - After initial placement the point may still get shifted due to the resampling and interpolation used. Long sections between stroke samples may get subdivided and the positions of the two samples are linearly interpolated. However, the interpolation starts at 1/n, meaning the first interpolated point never matches the first sample. This is correct for later samples where the last point should not be repeated, but it ends up moving the first curve point again when the 2nd sample is processed. This patch fixes both issues by keeping the first generated point stationary and never touching its position again. Pull Request: https://projects.blender.org/blender/blender/pulls/121011
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
#include "BLI_length_parameterize.hh"
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_geom.h"
|
||||
|
||||
@@ -35,11 +36,22 @@ static constexpr float POINT_OVERRIDE_THRESHOLD_PX = 3.0f;
|
||||
static constexpr float POINT_RESAMPLE_MIN_DISTANCE_PX = 10.0f;
|
||||
|
||||
template<typename T>
|
||||
static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst)
|
||||
static inline void linear_interpolation(const T &a,
|
||||
const T &b,
|
||||
MutableSpan<T> dst,
|
||||
const bool include_first_point)
|
||||
{
|
||||
const float step = 1.0f / float(dst.size());
|
||||
for (const int i : dst.index_range()) {
|
||||
dst[i] = bke::attribute_math::mix2(float(i + 1) * step, a, b);
|
||||
if (include_first_point) {
|
||||
const float step = math::safe_rcp(float(dst.size() - 1));
|
||||
for (const int i : dst.index_range()) {
|
||||
dst[i] = bke::attribute_math::mix2(float(i) * step, a, b);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float step = 1.0f / float(dst.size());
|
||||
for (const int i : dst.index_range()) {
|
||||
dst[i] = bke::attribute_math::mix2(float(i + 1) * step, a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,8 +378,13 @@ struct PaintOperationExecutor {
|
||||
const ColorGeometry4f prev_vertex_color = drawing_->vertex_colors().last();
|
||||
|
||||
/* Overwrite last point if it's very close. */
|
||||
const IndexRange points_range = curves.points_by_curve()[curves.curves_range().last()];
|
||||
const bool is_first_sample = (points_range.size() == 1);
|
||||
if (math::distance(coords, prev_coords) < POINT_OVERRIDE_THRESHOLD_PX) {
|
||||
curves.positions_for_write().last() = self.placement_.project(coords);
|
||||
/* Don't move the first point of the stroke. */
|
||||
if (!is_first_sample) {
|
||||
curves.positions_for_write().last() = self.placement_.project(coords);
|
||||
}
|
||||
drawing_->radii_for_write().last() = math::max(radius, prev_radius);
|
||||
drawing_->opacities_for_write().last() = math::max(opacity, prev_opacity);
|
||||
return;
|
||||
@@ -395,10 +412,11 @@ struct PaintOperationExecutor {
|
||||
MutableSpan<float> new_opacities = drawing_->opacities_for_write().slice(new_points);
|
||||
MutableSpan<ColorGeometry4f> new_vertex_colors = drawing_->vertex_colors_for_write().slice(
|
||||
new_points);
|
||||
linear_interpolation<float2>(prev_coords, coords, new_screen_space_coords);
|
||||
linear_interpolation<float>(prev_radius, radius, new_radii);
|
||||
linear_interpolation<float>(prev_opacity, opacity, new_opacities);
|
||||
linear_interpolation<ColorGeometry4f>(prev_vertex_color, vertex_color, new_vertex_colors);
|
||||
linear_interpolation<float2>(prev_coords, coords, new_screen_space_coords, is_first_sample);
|
||||
linear_interpolation<float>(prev_radius, radius, new_radii, is_first_sample);
|
||||
linear_interpolation<float>(prev_opacity, opacity, new_opacities, is_first_sample);
|
||||
linear_interpolation<ColorGeometry4f>(
|
||||
prev_vertex_color, vertex_color, new_vertex_colors, is_first_sample);
|
||||
|
||||
/* Update screen space buffers with new points. */
|
||||
self.screen_space_coords_orig_.extend(new_screen_space_coords);
|
||||
|
||||
Reference in New Issue
Block a user