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));
}
}