1.概述
Android的触控重采样算法非常出色。Android使用触摸外推和触摸内插的组合。触摸插值意味着我们接受两个触摸事件,并在两个触摸事件中间的某个位置创建一个触摸事件。触摸外推意味着我们进行两次触摸事件,并在上一次触摸事件之前的某个位置创建一个触摸事件,或者预测触摸事件的位置。让我们从60hz的LCD刷新显示速率和100hz的触摸屏刷新扫描速率来看一下我们的标准输入。
我们每10毫秒移动一次触摸输入事件,每10毫秒移动一次像素,每16.6毫秒刷新一次刷新显示vsync事件。Android的算法会创建一个称为“采样时间”的新计时事件,该事件始终比vsync事件晚5毫秒。因此,第一个采样时间为时间st = 11 ms(16个vsync时间-5个采样时间),然后下一个采样时间事件为时间st = 27 ms(32 ms vsync-5),下一个采样时间为43 ms( 48-5)。让我们看一下与采样时间相同的图:
采样时间用于平衡和确定触摸事件是外推还是内插。我们只看最后两个真实的触摸事件,而不看采样事件。如果最后一次触摸事件发生在采样时间之后,但在垂直同步时间之前,我们进行插值。例如,这发生在时间vsync t = 32 ms。采样时间为时间st = 27 ms,但是我们有两个触摸事件。在时间t1 = 20 ms和时间t2 = 30 ms发生一次触摸事件。由于上一次触摸事件t2在30毫秒后27毫秒之后,我们对这两个触摸事件进行插值。如果最后一次触摸事件发生在采样时间之前,则我们推断触摸事件。例如,在vsync事件t = 48毫秒时,我们的采样时间为st = 43毫秒。上一次触摸事件发生在时间t = 40 ms,即采样时间之前。我们将使用时间t1 = 30ms和t2 = 40ms的最后两个触摸事件来推断vsync事件t = 48的触摸事件。如果在采样时间之后(而不是垂直同步时间之后)存在触摸事件,我们将插入最后两次触摸。如果两个触摸事件都在采样时间之前发生,则我们推断出最后两个触摸事件。
2.插补
让我们看一下插值的情况。这不是简单的中点插值,因为它会考虑相对于采样时间发生触摸事件的时间。首先,我们计算两次最后一次触摸事件之间经过的时间,我们称其为触摸时间差。每个设备应该相对稳定。在我们的情况下,这应该始终为10毫秒。接下来,我们计算采样时间与触摸事件之间的时间差,即采样时间之前的时间(触摸采样差异)。对于我们在vsync t = 32的示例,采样时间为27ms。采样时间之前的第一次触摸事件为t = 20ms。因此,27 ms的采样时间-20 ms的触摸时间= 7ms。接下来,我们创建一个名为alpha的变量,它是触摸样本差异/触摸时间差异。在这种情况下,7 ms / 10 ms = 0.7。最后,我们使用此alpha值作为采样时间之后的触摸事件与采样时间之前的触摸事件之间的中点修饰符进行线性插值。我们的两个触摸事件分别在时间t = 20,位移d = 20和t = 30且位移d = 30。我们首先使用样本之前的第一个触摸事件,然后向其添加插值位移。因此,我们有一个内插位移d = 20 +(30-20)* alpha,它是20 +(10 * 0.7)=27。因此,在vsync时间t = 32时,我们发送一个位移为d =的触摸事件27。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们的两个触摸事件分别在时间t = 20,位移d = 20和t = 30且位移d = 30。我们首先使用样本之前的第一个触摸事件,然后向其添加插值位移。因此,我们有一个内插位移d = 20 +(30-20)* alpha,它是20 +(10 * 0.7)=27。因此,在vsync时间t = 32时,我们发送一个位移为d =的触摸事件27。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们的两个触摸事件分别在时间t = 20,位移d = 20和t = 30且位移d = 30。我们首先使用样本之前的第一个触摸事件,然后向其添加插值位移。因此,我们有一个内插位移d = 20 +(30-20)* alpha,它是20 +(10 * 0.7)=27。因此,在vsync时间t = 32时,我们发送一个位移为d =的触摸事件27。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们发送位移为d = 27的触摸事件。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:我们发送位移为d = 27的触摸事件。较大的alpha表示我们更倾向于最后一次触摸事件,而较低的alpha表示我们更倾向于第一次触摸事件。这是方程式:
这是一般的方程式。LastTouch指的是SampleTime之前的触摸。FirstTouch指的是SampleTime之前的触摸。
让我们看另一个示例,在vsync时间t = 80处。我们有两个触摸事件,一个在时间t = 70,另一个在时间t = 80。我们的采样时间是80毫秒-5 = 75毫秒。由于在采样时间之后发生一次触摸事件t = 80,因此我们进行插值。这是工作:
我们看到了位移d = 75的最终结果。插值就是这样。
3.外推法
当最后一次触摸事件在采样时间之前发生时,发生触摸外推。这发生在垂直同步时间t = 48。我们的采样时间是48-5 = 43毫秒。我们有两个触摸事件,一个在时间t = 30,另一个在时间t = 40 ms。由于两者均在43毫秒之前,因此我们推断触摸事件。逻辑工作原理与触摸插值类似,但有一些区别。两个触摸事件之间的触摸时间差仍然相同,始终为10 ms。接下来,我们计算触摸采样差,现在是最后一次触摸事件减去采样时间,因此我们期望一个负数。因此,我们将最后一次触摸事件设为t = 40-采样时间st = 43 = -3。接下来,我们以相同的方式计算Alpha,即触摸样本差异/触摸时间差异。这种情况是(-3 / 10)= -0.3。最后,我们再次使用相同的线性插值方程,但是由于alpha为负,因此我们可以推断。此外,我们交换操作数,并从最后一次触摸中减去第一次触摸,并将起始位移设置为最后一次触摸。因此,与插值算法不同,我们从最后一次触摸事件开始,并为其添加位移。我们的最终结果是位移d = 40 +(30-40)* -0.3 =43。因此,在这种情况下,我们推断了3个像素。这是所有的数学运算:
这是一般的外推方程。最后触摸是指最近的触摸。首次触摸是指较早的触摸事件。我们仍然使用最后两个触摸事件进行推断。
让我们在vsync时间t = 128 ms处再做一次推断。这是最终位移d = 123ms的工作。
如果我们对原始输入进行内插和外推,这是最终的位移图:
哇。哇 在第一帧之外,因为我们没有额外的触摸事件,所以它达到了理想的情况,即每16毫秒移动16个像素的位移以实现完美的平滑滚动。它的帧均匀性标准偏差为0。更令人惊奇的是,这些公式可在不同的触摸屏刷新率下计算触摸插值和外推。例如,Mozilla的Flame参考设备的触摸刷新率为每13毫秒一次,而不是像Nexus 4那样每10毫秒一次,它仍然可以创建完美的平滑滚动。更令人惊奇的是,此算法解决了触摸驱动器的噪声问题,因为实际设备不会以完全正确的10 ms间隔发送触摸事件,它们会抖动,因此您会以9.9ms或10.5ms的间隔获得触摸事件。
4.总结
猛击的感觉更快,使整个系统不一定更流畅,但响应速度更快。在跟踪手指或进行慢速滚动时,我们还获得了滚动感觉也更加流畅的额外好处。在所有方面,与其他触摸算法相比,这是优越的。在快速滚动时,它比以前的采样算法更好地保持手指顺畅。在慢速滚动时,它可以平滑触摸事件,从而提供流畅的体验。