我用html5画布模拟共振效果,使弹簧达到共振时动画。 还得到jquery ui滑块(最大范围),在动画期间动态地改变振荡的频率(w)。问题是当它发生变化时,由于某种原因,正弦波在某些点处破碎并且动画不平滑。这只有在改变频率时才会发生,振幅会更好。 我渲染每个帧的主要功能是:
function doSways() {
var spring = springs[0],
a = 0,
A = params.standParams.A,
w = params.standParams.w;
animIntervalId = setInterval(function() {
ctx.clearRect(0, 0, cnvW, cnvH);
A = params.standParams.A;
w = params.standParams.w;
/*if (w < params.standParams.w) { // with this expression and commented <w = params.standParams.w> it works a bit smoother but still some issues can be noticed, for example sharp increases just after the new change of the frequency (w) on the slider
w += 0.01;
}*/
stand.y = A*Math.sin(a*degToRad*w) + offsetY;
stand.draw();
spring.draw(stand.y, A, w);
if (a++ >= 360) { // avoid overflow
a = 0;
}
},
25);
}
这里是我如何更改滑块上的频率(w)并将其分配给params.standParams.w
$( "#standfreq_slider" ).slider({
range: "max",
min: 1,
max: 25,
step: 1,
value: 5,
slide: function( event, ui ) {
params.standParams.w = parseInt(ui.value);
}
});
);
如果在doSways函数中的表达式有点工作但它会产生另一个问题,我需要知道滑动的方向以确定我需要+ =或 - = 0.01 .. 如何使一切工作理想?
问题插图直播 jsfiddle
答案 0 :(得分:1)
基于正弦曲线的基本公式:
V = V0 + A * sin(2 * pi * f * t + phi)
其中:
我们希望频率变化之前和之后的当前值(V)相同。为了做到这一点,我们需要在变化之前和之后的频率(f)和阶段(phi)。
首先,我们可以将第一个等式设置为等于第二个等式:
V0 + A * sin(2 * pi * f1 * t + phi1) = V0 + A * sin(2 * pi * f2 * t + phi2)
做一些取消:
2 * pi * f1 * t + phi1 = 2 * pi * f2 * t + phi2
解决最终公式的新阶段:
phi2 = 2 * pi * t * (f1 - f2) + phi1
更多mathy版本:
编辑:
答案 1 :(得分:0)
我在下面解释的模式是我经常使用的模式 (它可能有一个名字 - 请S.O.人们告诉我,如果是这样的话。)
以下是这样的想法:每当您需要以平稳的方式进行属性演变时,您必须区分目标值和当前值。如果出于某种原因,目标值发生变化,则只会以您决定的方式影响当前值。
要从当前值获取目标值,您有多种方法:
•最简单:只需在每个刻度上与给定比率更接近:
current += ratio * (target-current);
其中比率为[0,1],0.1可能没问题。您可以看到,在第一次打勾时,比率== 1,当前==目标 请注意,此解决方案依赖于帧速率,并且您可能希望将值阈值化以在某个时刻获得相同的值,请探索:
var threshold = 0.01 ;
if (Math.abs(target-current)<threshold) current = target;
•您也可以以给定的速度达到目标:
var sign = (target - current) > 0 ? 1 : -1;
current += sign * speedToReachTarget * dt;
现在我们不依赖于帧速率(你必须正确处理帧时间),但如果你没有应用最小值/最大值和阈值,你将会“弹跳”:
if (Math.abs(target-current)<0.01) {
current = target;
return;
}
var sign = (target - current) > 0 ? 1 : -1;
current += sign * speedToReachTarget * dt;
current = (( sign > 0) ? Math.min : Math.max )( target, current);
•您可以使用许多其他类型的插值/缓动。