Каждое интерактивное устройство живёт в прошлом. Курсор на экране, точка касания пера, поворот камеры в шлеме виртуальной реальности - все эти положения отражают состояние руки пользователя с опозданием в десятки миллисекунд, потому что сигнал проходит длинную цепочку: сенсор, контроллер, шина, операционная система, очередь событий, рендер-движок и, наконец, скан-аут дисплея. Инженеры давно перестали просто сокращать эту цепочку и начали её обманывать: система предугадывает, куда движется рука, и рисует не то, что было, а то, что, скорее всего, происходит прямо сейчас. Такая предикция ввода стала стандартным приёмом в самых разных областях - от сенсорных экранов планшетов до сетевых шутеров и VR-гарнитур. В статье разбирается, из чего складывается сквозная задержка, какие математические модели используют для экстраполяции движения, как предсказание работает в играх и виртуальной реальности и почему оно неизбежно ошибается на резких разворотах.
Анатомия задержки цепочки ввода
Прежде чем предугадывать, нужно понять, что именно компенсируется. Полная задержка от движения руки до фотона на сетчатке собирается из множества ступеней, и каждая добавляет свою долю.
Первая ступень - сам сенсор. Оптический датчик мыши делает снимки поверхности с частотой в десятки тысяч кадров в секунду и вычисляет смещение, но выдаёт отсчёт с задержкой от одной до восьми миллисекунд в зависимости от прошивки, сглаживания (само по себе формы фильтрации движения) и режима энергосбережения. Ёмкостный контроллер сенсорного экрана ситуация схожая: матрица электродов сканируется дискретно, и свежий отсчёт появляется не мгновенно.
Дальше сигнал идёт через шину. Классический USB с опросом 125 Гц добавляет до восьми миллисекунд только на ожидание кадра опроса; устройства с 1000 Гц снижают штраф до одной миллисекунды, с 8000 Гц - до доли миллисекунды ценой роста нагрузки на процессор.
Третья ступень - операционная система. События ввода складываются в очередь, маршрутизируются в оконную подсистему, применяются акселерационные кривые, затем данные доходят до приложения через его цикл сообщений. Если приложение опрашивает ввод раз в кадр, к моменту обработки отсчёт уже постарел на время кадра.
Четвёртая ступень - рендеринг. Игровой движок или рисовальщик интерфейса строит кадр, затем кадр ждёт синхронизации при включённой вертикальной синхронизации, после чего контроллер дисплея выполняет скан-аут - построчное выведение картинки. Панель вносит собственное время отклика пикселей. В сумме типичная цепочка "рука - экран" на обычном рабочем месте укладывается в диапазон от тридцати до восьмидесяти миллисекунд: сенсор 1-8 мс, шина 1-8 мс, ОС 2-10 мс, рендер и кадровый буфер 8-33 мс, скан-аут и панель ещё 5-15 мс. Для зрительно-моторной системы человека, чувствительной к рассогласованию уже на уровне 10-20 мс при непрерывном движении, этого более чем достаточно, чтобы движение ощущалось "ватным".
Ключевое наблюдение: задержка неравномерна по составу, но стабильна по величине. Стабильность означает, что её можно не только уменьшать, но и предсказывать - затормозить оценку будущего ровно на те миллисекунды, которые сигнал ещё проведёт в трубопроводе.
Экстраполяция и фильтры предсказания позиции
Математическое ядро предикции ввода - экстраполяция траектории по истории отсчётов. Самый простой вариант - линейная экстраполяция по скорости: из двух последних отсчётов вычисляется мгновенная скорость v как разность позиций, делённая на интервал, и позиция на момент кадра оценивается как последняя известная точка плюс v, умноженная на величину предсказываемой задержки. Рука человека на масштабе десятков миллисекунд движется почти прямолинейно, поэтому даже такая модель даёт заметное визуальное улучшение.
Следующая ступень - учёт ускорения. Квадратичная экстраполяция оценивает не только скорость, но и её изменение: позиция будущего кадра вычисляется по формуле равноускоренного движения. Это точнее на начинающихся и заканчивающихся движениях, но опаснее на шуме: дифференцирование дважды усиливает шум сенсора, и предсказанная точка начинает дрожать. Практические системы поэтому ограничивают коэффициент ускорения или клампят максимальный вынос предсказания вперёд.
Более изящный инструмент - фильтр Калмана. Он ведёт внутреннюю оценку состояния (позиция и скорость, иногда и ускорение), по каждому новому отсчёту выполняет два шага - предсказание состояния по математической модели движения и коррекцию по реальному измерению с весом, зависящим от оценённого шума сенсора и шума модели. Результат - сглаженная оценка позиции и скорости, которую затем можно безопасно экстраполировать на заданное число миллисекунд вперёд. Калмановский фильтр хорош тем, что естественно балансирует между сглаживанием и отзывчивостью: чем шумнее датчик, тем сильнее фильтр доверяет модели, и наоборот.
Лёгкий родственник Калмана - альфа-бета фильтр. Это калмановский фильтр с фиксированными, заранее выбранными коэффициентами усиления alpha и beta: alpha задаёт вес нового измерения в оценке позиции, beta - в оценке скорости. Он требует буквально нескольких умножений на отсчёт, не нуждается в оценке ковариаций и поэтому массово применяется там, где считать нужно на каждом событии ввода. Подбор коэффициентов - отдельное искусство: высокий beta делает предсказание резким и отзывчивым, но шумным, низкий - гладким, но отстающим.
Полный конвейер предикции в типичной реализации выглядит так:
- Приём сырых отсчётов сенсора с метками времени и выравнивание их на общую шкалу.
- Сглаживание и оценка скорости (и при необходимости ускорения) фильтром - Калмана или альфа-бета.
- Экстраполяция позиции на момент вывода целевого кадра с учётом измеренной сквозной задержки.
- Ограничение выноса предсказания: не дальше фиксированной доли задержки и не дальше фиксированного расстояния.
- Плавное затухание предсказания при потере уверенности - когда последние отсчёты противоречат модели.
Важная деталь - предсказание должно быть состыковано с реальностью без заметного скачка, поэтому системы обычно предсказывают не на всю задержку, а на 60-80 процентов от неё, оставляя запас на ошибку переполоха.
Предсказание касаний и пера на сенсорных экранах
На сенсорных экранах проблема стоит особенно остро: палец или перо двигются прямо перед глазами, и любое отставание нарисованного штриха от кончика пера видно невооружённым взглядом. Современные сенсорные контроллеры опрашивают матрицу с частотой 240 Гц и выше, но этого всё равно не хватает, чтобы штрих идеально следовал за рукой, потому что дисплей обновляется только 60-120 раз в секунду, а между отсчётом тачскрина и выводом пикселя проходит заметное время.
Частичный ответ - частота опроса плюс дисплеи на 120 Гц и выше: скан-аут короче, отставание меньше. Но и тут кадр строится из ввода возрастом несколько миллисекунд, поэтому стек применяет предсказание: планшетные интерфейсы экстраполируют траекторию пальца при скролле, рисовальные приложения предугадывают точку касания пера и дорисовывают штрих впереди актуальных данных. Если перо поддерживает наведение, задача упрощается: ховер-координаты дают траекторию ещё до касания, и фильтр начинает работу заранее.
Требование здесь - консервативность. Ошибка штриха невозвратима: чернила уже легли на виртуальный холст, поэтому предсказание применяют только к предпросмотру, а окончательную геометрию строят по реальным отсчётам. Пользователь видит отзывчивую линию, а приложение не рискует оставить ложный изгиб.
Отдельная техника - объединение датчиков: гироскоп и датчики наклона и давления пера помогают предсказывать не только позицию, но и толщину линии и момент касания.
Клиентская предикция в сетевых играх
Сетевая задержка на два-три порядка больше аппаратной: пинг 40 мс означает, что команда дойдёт до сервера и подтверждение вернётся примерно через 80 мс, а в трансатлантических матчах счёт идёт на 150-250 мс. Рисовать персонажа только после ответа сервера невозможно - управление ощущалось бы как через мокрую перчатку. Поэтому в современных сетевых играх действует схема клиентской предикции: клиент немедленно применяет ввод локально, симулирует своего персонажа тем же кодом, что и сервер, и рисует мгновенный результат игроку; одновременно ввод с номером кадра отправляется на сервер, а ответ сервера проверяется против локальной симуляции. Если локальный прогноз и серверное состояние совпали, ничего не происходит; если разошлись, выполняется согласование (reconciliation): клиент откатывается к авторитетному состоянию сервера и заново применяет все вводы, пришедшие после него.
Симметричный приём на сервере - компенсация задержки (lag compensation): при выстреле сервер отматывает позиции остальных персонажей назад на пинг стрелка и проверяет попадание по состоянию мира, которое стрелок реально видел на экране.
Файтинги и некоторые другие жанры пошли ещё дальше и внедрили откатную сетевую модель (rollback netcode). Вместо задержки ввода кадры жизни обоих игроков симулируются сразу по предсказанному вводу противника; когда реальные входные данные приходят, игра молча откатывается на несколько кадров и пересчитывает состояние с верными вводами. Если предсказание угадало ввод противника - а в файтингах ввод устойчив несколько кадров подряд - отката зрительно не было вовсе. Если не угадало, игроки видят короткий "телепорт" на кадр-другой, что при 60 кадрах в секунду терпимо и несравнимо лучше постоянной задержки ввода на весь пинг.
Перепроекция движения и предикция в виртуальной реальности
Виртуальная реальность - самая чувствительная к задержке среда: картинка прилеплена к голове, и любое отставание при повороте вызывает не только дискомфорт, но и вестибулярное укачивание. Целевая планка "движение головы - новый кадр" в VR составляет около 20 мс, и даже дисплеи на 90-120 Гц сами по себе не решают задачу, если контент не успевает рендериться в такт.
Географически главный приём здесь - перепроекция. Асинхронный временной сдвиг (asynchronous timewarp) берёт уже готовый кадр, дождаться следующего нет времени, и перед скан-аутом искажает его под самый свежий поворот головы, считанный с трекинга в последний момент. Кадр поворачивается как плоская текстура вокруг зрителя, и с точки зрения вестибулярного аппарата отставание почти исчезает. Пространственный сдвиг (spacewarp) идёт дальше: он синтезирует промежуточные кадры между соседними отрендеренными, оценивая движение пикселей по оптическому потоку, и фактически удваивает выходную частоту при половинной частоте рендеринга.
Поверх перепроекции работает и предикция трекинга собственно: гироскопы шлема опрашиваются с частотой порядка 1000 Гц, из их потока фильтром оцениваются угловая скорость и ускорение головы, и поза предугадывается на момент середины скан-аута текущего кадра. Повороты головы предсказываются уверенно, потому что голова инертна и не меняет направление мгновенно; быстрые линейные смещения предсказываются хуже, поэтому timewarp исторически компенсировал только вращение.
Где предикция ошибается и что происходит дальше
Любая экстраполяция основана на допущении плавности. Резкий разворот - стоп и обратный ход мыши, смена направления штриха, рывок головы - нарушает это допущение, и предсказание выбрасывает точку в зону, куда рука не собиралась. Насколько большой будет видимая ошибка, зависит от глубины предсказания: при выносе на 15 мс и скорости 2 м/с максимальный промах порядка трёх сантиметров, что на экране вполне заметно.
Реакция систем на промах стандартизована. В сетевых играх несовпадение предсказания с сервером приводит к явлению "резиновая лента": клиент откатывается к серверному состоянию и персонаж рывком возвращается на несколько метров назад, а камера дёргается. В файтингах с откатом ошибка выглядит как мгновенный "телепорт" позы на один кадр. В рисовальных приложениях неправильно предсказанный предпросмотр штриха затухает или перерисовывается по реальным отсчётам. В VR промах по повороту головы обнажается как двойное изображение или "дрожание" мира на один кадр, пока timewarp не подхватит свежую позу. Все системы применяют одну и ту же страховку: ограничивают горизонт предсказания и плавно смешивают предсказанное и действительное состояние, чтобы поправка не читалась как скачок.
А существует ли принципиальный предел предсказуемости? Для пользовательского ввода квантовая неопределённость и не нужна: движение руки ограничено физиологией, и это положительная новость. Мышцы человека развивают ограниченную силу, суставы имеют ограниченный момент инерции, а нервный импульс обрабатывается с постоянными задержками порядка сотен миллисекунд. Всё вместе означает, что ускорение кончика пальца или руки с мышью не может измениться мгновенно на произвольную величину: на горизонте 8-20 мс траектория детерминирована с точностью, достаточной для коррекции на кадр вперёд. Предел предсказания упирается не в физику, а в целенаправленные решения самого человека - момент, когда он решил остановиться или развернуться, предсказать нельзя, можно только быстро обнаружить и компенсировать. Именно поэтому архитектуры предикции всегда парные: экстраполятор предсказывает, а механизм согласования незаметно извиняется за него, когда человек оказался изобретательнее модели.