event.movement, возвращающий нечетные значения

Я играл с webGL, и я достиг стадии, когда я могу делать маленькие трехмерные игры с очень жалкой графикой (это больше доказательство концепции / функциональности на данный момент). Для получения трехмерного опыта удобно перемещать мышь в любом направлении бесконечно и плавно, чтобы вращать камеру от первого лица. Pointerlock позволяет мне блокировать и скрывать положение курсора, что очень полезно, но тогда мне нужно найти другой метод отслеживания движений мыши. В моем исследовании event.movementX а также event.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 чтобы предотвратить массивные повороты в углу камеры, но я все еще остаюсь с очень раздражающим движением. Любые идеи, чтобы исправить или заменить более плавное движение интерфейса?

3 ответа

Решение

Это может быть полезно, если вы каким-то образом ограничите свое движение мышью. Например, версия дроссельной заслонки:

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

С таким подходом handleMouseMove не будет выполняться более 1 раза за 75мс.

Я знаю, что очень опаздываю на вечеринку, но у меня есть объяснение первой проблемы, упомянутой в OP, и решение второй проблемы, поднятой @KiranKota.

Первая проблема на самом деле является ошибкой в ​​версиях Chromium до 67. Она бездействовала, пока что-то не произошло в обновлении Windows 10 Fall Creator, которое в конечном итоге раскрыло ее. Даже если вы находитесь в режиме блокировки указателя, ваш «курсор», хотя и невидимый, по сути, будет перемещаться по другую сторону окна, вызывая всплески в противоположном направлении движения.

Чтобы исправить это, просто игнорируйте первое событие перемещения мыши, которое движется в противоположном направлении; это если вы все еще заботитесь о поддержке Chromium <67.

Вторая проблема, когда шипы движутся в одном направлении, совершенно не связана и остается проблемой для Chromium 94. Проблема связана с мышами с высокой частотой опроса, как в случае со многими игровыми мышами. В ходе своих экспериментов я обнаружил, что частота опроса 1000 - это очень плохо, 500 - меньше, а 250, похоже, устраняют проблему. Я также обнаружил, что шипы соответствуют ширине текущего окна. Это всегда window.innerWidth / 2.272727 ... плюс то, что я могу только предположить, это «реальное» расстояние текущего движения мыши. Почему 2.272727...? Я понятия не имею. Фактор один и тот же, независимо от того, бегаю ли я со скоростью 1000 или 500.

Ось Y еще более странная. Движение вверх приводит к скачкам, равным window.innerHeight / 1,44, а движение вниз - в 5,21 раза.

Я собираюсь поэкспериментировать с этим еще и посмотреть, смогу ли я надежно отфильтровать эти аномалии. А пока, возможно, эта информация будет полезна.

У меня была такая же проблема, но для меня плохие значения всегда совпадают с направлением движения. Я обнаружил, что если я заменяю любые значения выше 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));
  }
}
Другие вопросы по тегам