2

我一直在玩 webGL,我已经达到了可以制作带有非常可怜的图形的小型 3D 游戏的地步(到目前为止,它更像是概念/功能的证明)。对于3D体验,任意方向无限移动鼠标,旋转第一人称摄像头,效果非常好。Pointerlock 允许我锁定和隐藏光标位置,这非常有帮助,但是我需要找到另一种跟踪鼠标移动的方法。在我的研究中,event.movementXevent.movementY似乎是标准,但我经常在鼠标移动的相反方向上出现大的移动(通常在 500 到 583 之间)。我用许多鼠标和触控板对此进行了测试,并遇到了同样的现象。

这是我的相关事件侦听器:

document.addEventListener("mousemove", function(event) {
   xMovement += event.movementX; 
   yMovement += event.movementY; 
   console.log(event.movementX)
}, false);

document.addEventListener("pointerlockchange", function(event) {
   if(pointerLockEnabled) pointerLockEnabled = false; 
   else pointerLockEnabled = true; 
   xMovement = 0; yMovement = 0; 
} , false);

以及相关的渲染循环代码:

function render() {
   if(pointerLockEnabled) {
       camera.rotation.y = -xMovement / 1000;
       camera.rotation.x = -yMovement / 1000;
       if(rightKey && !leftKey) {
          camera.position.x += 10 * Math.cos(camera.rotation.y);
          camera.position.z -= 10 * Math.sin(camera.rotation.y);
       }
       else if(leftKey && !rightKey) {
          camera.position.x -= 10 * Math.cos(camera.rotation.y);
          camera.position.z += 10 * Math.sin(camera.rotation.y);
       }
       if(upKey&& !downKey) {
          camera.position.z -= 10 * Math.cos(camera.rotation.y);
          camera.position.x -= 10 * Math.sin(camera.rotation.y);
       }
       else if(downKey && !upKey) {
          camera.position.z += 10 * Math.cos(camera.rotation.y);
          camera.position.x += 10 * Math.sin(camera.rotation.y);
       }
   }
}

但是我的控制台出现了这样的情况:

控制台捕获

我添加了更改条件xMovement以防止摄像机角度发生大幅转动,但我仍然留下非常烦人的运动。有什么想法可以修补或替换为更无缝的界面移动吗?

4

3 回答 3

1

如果您以某种方式限制 mousemove 事件,这可能会有所帮助。例如lodash 油门版本:

function handleMouseMove(event) {
   xMovement += event.movementX; 
   yMovement += event.movementY; 
   console.log(event.movementX)
}
var throttledHandleMouseMove = _.throttle(handleMouseMove, 75);
document.addEventListener("mousemove", throttledHandleMouseMove, false);

使用这种方法handleMouseMove,每 75 毫秒执行的次数不会超过 1 次。

于 2018-01-10T03:48:52.343 回答
0

我有同样的问题,但对我来说,糟糕的价值观总是与运动的方向相同。我发现如果我用最后一个值替换任何高于 50 的值,我会得到非常好的准确性。唯一的问题是当错误值在 30-49 范围内时,但我不想取消这些,以防用户实际上快速移动鼠标或鼠标的轮询率不佳。一些趋势线比较可以用来平滑这些,但如果你不需要太高的精度,这很好:

const movement = {X: 0, Y: 0};
const lastMovement = {X: 0, Y: 0};
function onMouseMove(evt) {
  if (checkPointerLock()) {
    ['X', 'Y'].forEach(axis => {
      const checkValue = evt['movement' + axis] || evt['mozMovement' + axis]|| 0;
      //ignore >=50. probably erroneous. smooth to last value
      if (Math.abs(checkValue) < 50) {
        lastMovement[axis] = checkValue;
      }
      movement[axis] = lastMovement[axis];
    });

    yaw += movement.X * -0.001 * data.sensitivityX;
    pitch += movement.Y * (data.invertY ? .001 : -.001) * data.sensitivityY;
    pitch = Math.max(-Math.PI/2, Math.min(Math.PI/2, pitch));
  }
}
于 2020-11-26T18:22:40.917 回答
0

我知道我在这里参加聚会已经很晚了,但是我对 OP 中提到的第一个问题有一个解释,并且对@KiranKota 提出的第二个问题有一个解决方法。

第一个问题实际上是 64 之前的 Chromium 版本中的一个错误。它一直处于休眠状态,直到 Windows 10 Fall Creator 的更新中发生了一些事情,最终暴露了它。即使您处于指针锁定状态,您的“光标”虽然不可见,但实际上会绕到窗口的另一侧,从而在相反的运动方向上产生尖峰。

对此的解决方法是简单地忽略向相反方向移动的第一个鼠标移动事件;那是如果您仍然关心支持 Chromium < 67。

第二个问题,即尖峰向同一方向移动,完全不相关,并且在 Chromium 94 中仍然是一个问题。这个问题与高轮询率的鼠标有关,就像许多游戏鼠标一样。通过我的实验,我发现 1000 的轮询率非常糟糕,500 更少,而 250 似乎使问题消失了。我还发现尖峰与当前窗口的宽度一致。它们总是 window.innerWidth (or innerHeight) / ~2.3... ,加上我只能假设是当前鼠标移动的“真实”距离。为什么是 2.3-ish...?我不知道。无论我以 1000 还是 500 的速率运行,这个因素都是相同的。

我将对此进行更多试验,看看我是否不能可靠地过滤掉这些异常。与此同时,也许这些信息会有用。

于 2021-10-22T06:21:50.627 回答