好吧,我一直在创建一个 UI 框架并向其中添加动画。我想让用户使用cubicBeziers控制动画的计时功能,所以我决定使用p5.js的
bezierPoint()
函数。我花了几个小时让它工作,终于让它以我认为完美的方式工作......直到现在我发现它(不知何故)没有按预期工作。
当我传入一个起点/终点位于
0,1
和 1,0
且控制点位于 0.5,0.5
和 0.5,0.5
的三次贝塞尔曲线(这是线性三次贝塞尔曲线)时,我会得到一个 eased 动画,无需任何操作。原因...这应该会产生线性动画(可以在here进行演示),但不知何故它不是。
所以我进一步研究它只是为了证明我不仅仅是看到东西,而且果然,它实际上给出了非线性数字。我写了这个小代码片段:
<script src = "https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.min.js"></script>
<script>
function setup(){
createCanvas(100,100);
}
function draw(){
background(255,255,0);
noFill();
stroke(0,0,0);
strokeWeight(3);
bezier(0,100,50,50,50,50,100,0);
ellipse(bezierPoint(0,50,50,100,frameCount / 100),bezierPoint(100,50,50,0,frameCount / 100),5,5);
ellipse(50,bezierPoint(100,50,50,0,frameCount / 100),5,5);
ellipse(60,100 - frameCount,5,5);
}
</script>
您可以非常清楚地看到,与线性速度(右侧的点)相比,
bezierPoint()
(左侧的点)后面的点以非线性速度移动
为什么会出现这种情况?
只是为了方便起见我将其包含在这里。这是 p5.js 的
bezierPoint()
函数:
function bezierPoint(e,t,r,i,n){
var a = 1 - n;
return(Math.pow(a,3) * e + 3 * Math.pow(a,2) * n * t + 3 * a * Math.pow(n,2) * r + Math.pow(n,3) * i);
}
当三次贝塞尔曲线的 4 个控制极点共线时,贝塞尔曲线确实会看起来“线性”。但这并不意味着这条贝塞尔曲线与从 P0 到 P3 的直线完全相同。直线的一阶导数是常数,但线性贝塞尔曲线的一阶导数不是常数(一般情况下)。
要获得“真正的”线性三次贝塞尔曲线,需要将两个中间控制点 P1 和 P2 放置在
P1 = P0 + (P3-P0)/3
P2 = P0 + 2*(P3-P0)/3
好吧,经过继续研究,这似乎是预期的行为不知何故。
我发现了这个问题:使用三次贝塞尔函数自定义动画
其中指出“我在一个问题上看到回答者建议简单地消除 x 并将函数定义为 y 针对 t。但是,这会给出非常不准确的结果,因为从 0.0 到 1.0 的线性贝塞尔曲线不会线性动画。 ”
这让我意识到我在这里看到的是某种预期的行为。我就是无法用我的大脑来解决它。