早些时候,我试图找出如何使用 p5.js 围绕枢轴旋转一条线,我稍微修改了一下代码,使用
atan2
函数使线指向鼠标。它工作得很好,我决定看看如果我使用线性插值 (lerp
) 来使动画看起来更平滑,会是什么样子。奇怪的是,这条线似乎一旦经过某个点,就会跳到另一边,而不是仅仅移动到该点。
这是我遇到问题的代码:
let angle = 0;
let rot = 0;
function setup() {
createCanvas(600, 300);
}
function draw() {
let v1 = createVector(width / 2 - 50, height / 2);
let v2 = createVector(width / 2 + 50, height / 2);
background(255);
stroke(0);
strokeWeight(4);
rot = lerp(rot, atan2(mouseY - v1.y, mouseX - v1.x), 0.1);
push();
translate(v1.x, v1.y);
rotate(rot);
translate(-v1.x, -v1.y);
let r0 = line(v1.x, v1.y, v2.x, v2.y);
strokeWeight(10);
let p1 = point(v1.x, v1.y);
let p2 = point(v2.x, v2.y);
pop();
}
怎样才能让这个动画看起来流畅,没有奇怪的跳跃?
问题是因为
atan
返回 -Math.PI
到 +Math.PI
之间的值,因此在表达式 target_angle = atan2(mouseY - v1.y, mouseX - v1.x)
的线性插值失败的地方存在跳跃。
这就是为什么,为了使当前
rot
到 target_angle
之间的路径最短,我们应该对两者之间的差异进行归一化,以便覆盖其 abs
值的距离应小于 Math.PI
(半圆)
let angle = 0;
let rot = 0;
function setup() {
createCanvas(600, 300);
}
function draw() {
let v1 = createVector(width / 2 - 50, height / 2);
let v2 = createVector(width / 2 + 50, height / 2);
background(255);
stroke(0);
strokeWeight(4);
let target = atan2(mouseY - v1.y, mouseX - v1.x);
while (target - rot > Math.PI) {
target -= 2 * Math.PI;
}
while (target - rot < -Math.PI) {
target += 2 * Math.PI;
}
rot = lerp(rot, target, 0.1);
push();
translate(v1.x, v1.y);
rotate(rot);
translate(-v1.x, -v1.y);
let r0 = line(v1.x, v1.y, v2.x, v2.y);
strokeWeight(10);
let p1 = point(v1.x, v1.y);
let p2 = point(v2.x, v2.y);
pop();
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>