Skip to content

Commit

Permalink
Handle corner cases for curve baking
Browse files Browse the repository at this point in the history
When control point and point have equal position,
the derivative is 0 vector, which cause error message in Basis::look_at().
This commit handles this case.
  • Loading branch information
xiongyaohua committed Dec 8, 2022
1 parent cf093f8 commit 32803cf
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 11 deletions.
16 changes: 16 additions & 0 deletions core/math/vector2.h
Expand Up @@ -113,6 +113,7 @@ struct _NO_DISCARD_ Vector2 {
_FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
_FORCE_INLINE_ Vector2 bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
_FORCE_INLINE_ Vector2 bezier_tangent(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;

Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;

Expand Down Expand Up @@ -289,6 +290,21 @@ Vector2 Vector2::bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_
return res;
}

Vector2 Vector2::bezier_tangent(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
Vector2 res = *this;

// Handle corner cases.
if (Math::is_zero_approx(p_t - 0.0f) && p_control_1.is_equal_approx(res)) {
return (p_end - res).normalized();
}

if (Math::is_zero_approx(p_t - 1.0f) && p_control_2.is_equal_approx(p_end)) {
return (p_end - res).normalized();
}

return res.bezier_derivative(p_control_1, p_control_2, p_end, p_t).normalized();
}

Vector2 Vector2::direction_to(const Vector2 &p_to) const {
Vector2 ret(p_to.x - x, p_to.y - y);
ret.normalize();
Expand Down
16 changes: 16 additions & 0 deletions core/math/vector3.h
Expand Up @@ -101,6 +101,7 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
_FORCE_INLINE_ Vector3 bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
_FORCE_INLINE_ Vector3 bezier_tangent(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;

Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;

Expand Down Expand Up @@ -270,6 +271,21 @@ Vector3 Vector3::bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_
return res;
}

Vector3 Vector3::bezier_tangent(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
Vector3 res = *this;

// Handle corner cases.
if (Math::is_zero_approx(p_t - 0.0f) && p_control_1.is_equal_approx(res)) {
return (p_end - res).normalized();
}

if (Math::is_zero_approx(p_t - 1.0f) && p_control_2.is_equal_approx(p_end)) {
return (p_end - res).normalized();
}

return res.bezier_derivative(p_control_1, p_control_2, p_end, p_t).normalized();
}

real_t Vector3::distance_to(const Vector3 &p_to) const {
return (p_to - *this).length();
}
Expand Down
7 changes: 2 additions & 5 deletions editor/plugins/path_3d_editor_plugin.cpp
Expand Up @@ -274,13 +274,10 @@ void Path3DGizmo::redraw() {

// Fish Bone.
v3p.push_back(p1);
v3p.push_back(p1 + (side - forward) * 0.06);
v3p.push_back(p1 + (side - forward + up * 0.3) * 0.06);

v3p.push_back(p1);
v3p.push_back(p1 + (-side - forward) * 0.06);

v3p.push_back(p1);
v3p.push_back(p1 + up * 0.03);
v3p.push_back(p1 + (-side - forward + up * 0.3) * 0.06);
}

add_lines(v3p, path_material);
Expand Down
12 changes: 6 additions & 6 deletions scene/resources/curve.cpp
Expand Up @@ -835,19 +835,19 @@ void Curve2D::_bake() const {

// Collect positions and sample tilts and tangents for each baked points.
bpw[0] = points[0].position;
bfw[0] = points[0].position.bezier_derivative(points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0).normalized();
bfw[0] = points[0].position.bezier_tangent(points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0);
int pidx = 0;

for (int i = 0; i < points.size() - 1; i++) {
for (const KeyValue<real_t, Vector2> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key).normalized();
bfw[pidx] = points[i].position.bezier_tangent(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
}

pidx++;
bpw[pidx] = points[i + 1].position;
bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0).normalized();
bfw[pidx] = points[i].position.bezier_tangent(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
}

// Recalculate the baked distances.
Expand Down Expand Up @@ -1539,21 +1539,21 @@ void Curve3D::_bake() const {

// Collect positions and sample tilts and tangents for each baked points.
bpw[0] = points[0].position;
bfw[0] = points[0].position.bezier_derivative(points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0).normalized();
bfw[0] = points[0].position.bezier_tangent(points[0].position + points[0].out, points[1].position + points[1].in, points[1].position, 0.0);
btw[0] = points[0].tilt;
int pidx = 0;

for (int i = 0; i < points.size() - 1; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key).normalized();
bfw[pidx] = points[i].position.bezier_tangent(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
}

pidx++;
bpw[pidx] = points[i + 1].position;
bfw[pidx] = points[i].position.bezier_derivative(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0).normalized();
bfw[pidx] = points[i].position.bezier_tangent(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
btw[pidx] = points[i + 1].tilt;
}

Expand Down

0 comments on commit 32803cf

Please sign in to comment.