GPv3: Fix jittery miter points by the outline modifier

With the default GPv3 "Stroke" object the outline modifier generates
jittery strokes. It also generates full circles at various points along
the input stroke.

The outline modifier chooses a normal from the camera view. In the
default GPv3 stroke test the camera views the stroke from an angle.
In that case the curve has a significant Z component out of the plane,
which breaks normalization of the 2D component and causes excessive
miter scaling.

The full circles are caused by bad angles, the range should be `(-pi,pi)`
rather than `(0,2*pi)`.

Pull Request: https://projects.blender.org/blender/blender/pulls/119067
This commit is contained in:
Lukas Tönne
2024-03-05 11:07:45 +01:00
parent d6b1d00a0f
commit 3f43f83b8a
@@ -190,15 +190,20 @@ static void generate_arc_from_point_to_point(const float3 &from,
return;
}
const float dot = math::dot(vec_from.xy(), vec_to.xy());
const float det = vec_from.x * vec_to.y - vec_from.y * vec_to.x;
const float angle = math::atan2(-det, -dot) + M_PI;
const float cos_angle = math::dot(vec_from.xy(), vec_to.xy());
const float sin_angle = vec_from.x * vec_to.y - vec_from.y * vec_to.x;
const float angle = math::atan2(sin_angle, cos_angle);
/* Number of points is 2^(n+1) + 1 on half a circle (n=subdivisions)
* so we multiply by (angle / pi) to get the right amount of
* points to insert. */
const int num_points = std::max(int(((1 << (subdivisions + 1)) + 1) * (math::abs(angle) / M_PI)),
2);
const int num_full = (1 << (subdivisions + 1)) + 1;
const int num_points = num_full * math::abs(angle) / M_PI;
if (num_points < 2) {
r_perimeter.append(center_pt + vec_from);
r_src_indices.append(src_point_index);
return;
}
const float delta_angle = angle / float(num_points - 1);
const float delta_cos = math::cos(delta_angle);
const float delta_sin = math::sin(delta_angle);
@@ -259,8 +264,8 @@ static void generate_corner(const float3 &pt_a,
{
const float length = math::length(pt_c - pt_b);
const float length_prev = math::length(pt_b - pt_a);
const float3 tangent = math::normalize(pt_c - pt_b);
const float3 tangent_prev = math::normalize(pt_b - pt_a);
const float2 tangent = math::normalize((pt_c - pt_b).xy());
const float2 tangent_prev = math::normalize((pt_b - pt_a).xy());
const float3 normal = {tangent.y, -tangent.x, 0.0f};
const float3 normal_prev = {tangent_prev.y, -tangent_prev.x, 0.0f};
@@ -278,7 +283,7 @@ static void generate_corner(const float3 &pt_a,
r_src_indices);
}
else {
const float3 avg_tangent = math::normalize(tangent_prev + tangent);
const float2 avg_tangent = math::normalize(tangent_prev + tangent);
const float3 miter = {avg_tangent.y, -avg_tangent.x, 0.0f};
const float miter_invscale = math::dot(normal, miter);