标签:
最近在做一个移动设备上的触控系统需求,基本的要求点是:通过手指在屏幕上指定区域内的滑动点击来控制一个对象在空间或屏幕上的位置移动。具体的应用场合:
但是这里边会遇到一个问题,移动设备直接得到的Input中的touch信息其实是有噪声的,这些噪声一方面来自于硬件touch感应设备,另外一些来自于用记的操作,而噪声在使用中的表现就是转换后的信号会有较大的jag现象。比如用来控制一个屏幕上的光标,那么这个光标的位置可能就会一直抖动。因而如果对信息的平滑度要求过高的话必须得对这些原始的输入信号进行滤波才可以,即可输入的信号上施加一个低通滤波器,以便过滤掉其中的高频信息。
为了良好的用户体验,这里对需要的一个较合理的低通滤波器的设计要求是:
所以这里边就涉及到一个对速度的考量,即通过速度来确定需要过滤掉的信号的尺度,而对速度与位置的平滑则直接使用指数平滑(Exponential smoothing)。最终实现了一下,得到的效果还是比较理想的。对应的代码如下:
void LowPassFilter(Vector2 currentPosition, Vector2 currentVelocity, float dt) { if (Mathf.Approximately((currentVelocity - mFilteredVelocity).sqrMagnitude, 0)) { mFilteredVelocity = currentVelocity; } else { mFilteredVelocity = FilterKernel(currentVelocity, mFilteredVelocity, Alpha(Vector2.one, dt)); } if (Mathf.Approximately((currentPosition - mFilteredPosition).sqrMagnitude, 0)) { mFilteredPosition = currentPosition; } else { Vector2 cutoffFrequency; cutoffFrequency.x = mJitterReduction + 0.01f * mLagReduction * Mathf.Abs(mFilteredVelocity.x); cutoffFrequency.y = mJitterReduction + 0.01f * mLagReduction * Mathf.Abs(mFilteredVelocity.y); mFilteredPosition = FilterKernel(currentPosition, mFilteredPosition, ComputeExpSmoothingFactor(cutoffFrequency, dt)); } } Vector2 ComputeExpSmoothingFactor(Vector2 cutoff, float dt) { float tauX = 1 / (2 * Mathf.PI * cutoff.x); float tauY = 1 / (2 * Mathf.PI * cutoff.y); float alphaX = 1 / (1 + tauX / dt); float alphaY = 1 / (1 + tauY / dt); alphaX = Mathf.Clamp(alphaX, 0, 1); alphaY = Mathf.Clamp(alphaY, 0, 1); return new Vector2(alphaX, alphaY); } Vector2 FilterKernel(Vector2 current, Vector2 previous, Vector2 alpha) { float x = alpha.x * current.x + (1 - alpha.x) * previous.x; float y = alpha.y * current.y + (1 - alpha.y) * previous.y; return new Vector2(x, y); }运行效果动态截图如下(其中的jagReduction和lagReduction分别设置为1):
标签:
原文地址:http://blog.csdn.net/bugrunner/article/details/50818806