Комментарии 276
И раз уж такая тема, то что выбрать?
Есть ещё технология Nvidia Fast Sync. Для него не нужно специального монитора.
Так как нужна удвоенная часта кадров. Если монитор у вас 60 Герцовый, то FPS в игре должно быть не меньше 120.
Но это само собой работает только на мощных современных видеокартах и процессорах.
AMD FreeSync и Nvidia G-Sync — это по сути аппаратный vsync
GPU выдает кадры с различными промежутками времени — и монитор показывает кадры с различными промежутками времени
Ещё как влияя...
GPU выдает кадры с различными промежутками времени — и монитор показывает кадры с различными промежутками времени
Эти два высказывания противоречивы. Второе верно, монитор перестает влиять на частоту обновления и отображает только готовые кадры с GPU, которые в данном случае имеют существенный разброс времени рендеринга и делают картинку дерганой.
Еще раз, переменная частота кадров монитора не решает никаких проблем с рендерингом, она только устраняет разрыв кадра путем синхронизации обновления с GPU.
Прыгающие фреймтаймы никуда не деваются, только вот без VRR их пытаются запихнуть в фиксированные для 60гц 16.7мс, что во многих случаях значительно усугубляет проблему.
Фрисинк не панацея и от статеров не избавит, только вот визуально такое дерганное изображение с фрисинком и без — две большие разницы.
А вот от просто проседающего фпс (не статтеров) — фрисинк действительно панацея. Зачем резать фпс до 30, когда система выдает относительно стабильные 45? А зачем резать до 60, если система выдаёт все сто?
Если я правильно понял суть проблемы, эти технологии не могут решить проблему.
Приложение (игра) не получают реальных данных о том, сколько рендерился кадр и сколько он отображается, чтобы оно могло точно просчитать следующий кадр.
Простое решение есть — собрать машину на порядок мощнее, чем требуется, поставить игровым процессам самый высокий приоритет, отрубить все энергосберегайки, отключить предсказания о которых говорится в статье, и вуаля.
По большому счету в древних аркадах поэтому проблем и не было — все процессорное время пользовалось игрой и процессор работал со стабильной частотой.
Да, получается дорого и неэкологично, но для игровых компьютеров, я полагаю, вполне решение. Хотя и выглядит страшненько :)
Иногда так и есть. Сталкивался с ситуацией, когда загруженный седан (атмосферник, 1.5) глох при попытках заехать в горку (крутую). Пришлось отключить кондиционер.
Не понял. Как это — мы не можем узнать, когда кадр отображён? Разве момент привязки — не первый же Vertical Retrace после завершения рендеринга?
Это да. Но не вижу, как тут могут помочь какие-то API: не могу представить себе системный вызов, позволяющий заглянуть в будущее.
Интересно, кстати — насколько быстрее (в типовой игре) рендерится кадр более низкого разрешения? Можно ли рендерить в двух разрешениях, и если мы не успели отрендерить нужный кадр в высоком — отображать в низком? Или же (но тут придётся поизвращаться) отображать афинную трансформацию предыдущего кадра (просто привязав его по нескольким точкам к текущему — чтобы "вздрагивал" в этом случае не весь кадр, а только подвижные объекты)?
Проблема в том что swapBuffers может висеть довольно долго и реальное отображение будет неизвестно когда в этом промежутке, это не обязательно конец swap+glFinish и подобному. Вот это расширение позволяет узнать когда же оно реально было. В будущее никто не заглядывает, просто учитываешь это при генерации следующего кадра. Тут конечно еще может быть время пока кадр дойдет до монитора, но оно обычно уже постоянное и на «stutter» уже не влияет.
А разве мы не можем просто…
Можно просто. Если замеряемый fps около 60 то использовать указанный костыль, если видим что fps реально не успевает — выключаем костыль, действуем как обычно. Это, конечно, не идеально, но поскольку на уровне API решений нет, пока так сойдет…
На замыленный взгляд разработчика (у которого в голове «да от… тесь от меня») оно может быть вот прям почти нормально. Но именно на взгляд.
Из опыта: берём два одинаковых компа или ноутбука, ставим рядом, делаем им идеальную сеть, запускаем отыгрывать один и тот же сценарий.
На взгляд они вполне могут показывать одно и то же, ну, почти.
Но если включить звук — всё сразу становится понятно. На слух даже 1/100 рассинхрона моментально чувствуется. За 1/10 хочется убить.
Но если включить звук — всё сразу становится понятно. На слух даже 1/100 рассинхрона моментально чувствуется. За 1/10 хочется убить.
Вы когда в комнате разговариваете, то у вашего голоса с отраженным от стен эхом рассинхрон 1/100, и ничего.
А вот в играх, даже динамических и «задержко-зависимых» типа PUBG или Warthunder она практически не ощущается. Парадокс.
Да никакого парадокса, просто задержка там сильно больше, чем 1/100, вот и все.
Ну и на будущее про консоли добавлю — на PS4 есть remote play c аппаратным кодированием 720p 60fps, на Ps4Pro уже 1080p 60fps, без HDR. На Xbox One это тоже есть, а вот switch пока обделён — хотя это и неудивительно, свитч легче взять целиком. Вдруг пригодится
Купил 1080б а оно тормозит. Процессор проставивает, GPU простаивает — а оно тормозит.
Решил проблему тем, что в настройках игры выставил принудительную частоту кадров 60, а в драйвере включил FastSync.
Сразу стало плавно и никаких рассинхронизаций.
Движок не дурак — если не успевает рендерить 60fps, то сам «пропускает кадры».
Решается похожим способом:
Application.targetFrameRate = 60
Такой баг сложно воспроизвести. Скорее всего вы двигаете куб на константное значение в методе update, а надо константное значение умножать на Time.deltaTime. Тогда плавность будет нарушена только в очень редких случаях, как описано в статье
Vector3 velocity;
void Start() {
velocity = transform.forward;
}
void Update() {
transform.position += velocity * Time.deltaTime;
}
И как же, по вашему, может быть решена проблема, описанная в статье, используя методы FixedUpdate? По моему мнению, проблема, описанная в статье, на данный момент, нерешаема в общем виде. Только костылями. Если вы придумали решение, будь-те любезны показать пример кода.
Вообще я разрабатываю сетевые игры. Например RTS стратегию. У меня координаты смещения объектов вычисляются вообще в отдельном потоке или приходят по сети. А в Update идет интерполяция между старым и новым положением. В любом случае, transform.position должен меняться в методе Update и всегда по какой-то формуле, зависимой от времени. Только так получается достигнуть плавного движения. Буду рад увидеть код с другим решением.
В итоге будет плавающая задержка между фактическим отображением кадра и текущим состоянием мира, но она колеблется в слишком небольших пределах, чтобы на что-то влиять, эффектов торможения от этого не должно быть.
Вы это пробовали сами написать? У меня всегда в таких случая были только лаги. Так можно делать, если в Update пихать интерполяцию между старыми и новыми значениями, посчитанными в FixedUpdate(), но и то, объект то будет ускоряться то замедляться.
Рассмотрим пример. Пусть частота FixedUpdate() и Update () примерно равна. В FixedUpdate() мы изменяем координату на один. x+=1; В Update отображаем эту координату. За 9 итераций FixedUpdate выводит значение x {1,2,3,4,5,6,7,8,9}, Update вызывается без синзронизации, поэтому иногда он будут запаздывать, иногда брать значение раньше, чему нужно, может получиться к примеру {1,1,3,4,4,6,6,8,9} То есть иногда объект будет слишком спешить, иногда ждать.
Там даже есть delta именно для FixedUpdate.
На самом деле странное решение… перемещение объектов и камеры будет иметь ниже FPS чем у всяких эффектов при том что фреймрейт може быть высокий.
Там насколько помню частоту fixedUpdate можно поменять в настройках проекта. По умолчанию вроде 40 раз в секунду срабатывает. Можно поставить 100, этого будет более чем достаточно для плавности.
Но если вы используете какие-то сторонние ассеты и они написаны через ж..., то они начнут вести себя неадекватно при нестандартной частоте (сталкивался с таким).
Для этого есть FixedUpdate().Проявлятся будет в еще худшем виде. В какие-то кадры дерево может прыгнуть сразу на 2 шага вместо одного.
В свое время продюсер погонял насчет того, что дергается картинка при хорошем FPS. Потом выяснилось, что если Unity принудительно не ограничивать в кадрах, то колебания между 80-100 кадрами в секунду очень плохо влияет на плавность картинки.
Кстати, посмотрел ещё на картинку с таймингами фреймов, подумал… Но ведь бредовые же тайминги! 24.8 — ещё туда-сюда (допустим, картинка отображалась в течение двух кадров, значит, "центр масс" попадёт на середину между ними, смещение в полкадра. А 10.7 и 14.3 — это какой-то болезненный бред. Не может такого быть. Все числа должны быть кратны 16.6 (если считать по моменту отображения кадра), на крайняк 8.3 (если считать по "серединам" и кадры отображаются разное время).
Не-не-не, это не время рендеринга кадров (оно не может быть 16.6 — слишком много для 60 fps), это, насколько я могу судить, разница "физических" времён кадров (т.е. на какое время обсчитывается игровой мир в каждом кадре)
Именно поэтому. Нужен запас времени. А если обсчёт кадра занимает примерно 1/60 секунды — то даже крохотная задержка приведёт к тому, что мы не успеем вывести его вовремя, и выведем ещё на 1/60 секунды позже. Т.е. у нас половина кадров будет по 1/60 секунды, а половина по 2/60, гарантированное дрожание картинки.
эммм. помнится ещё в лохматые года было ж придумано, что игровой движок существует со своим "фпс", которым рассчитывается вся логика, а отображение идёт отдельно от него по принципу "как успеет". это ведь отображение только. там можно дропать кадры, перерисовывать/актуализировать когда угодно. это ж дурь полная, если физика, например, завязана на фпс видеокарты.
ну и в сетевых всех играх так 100% — ведь не может же течение игрового времени для всех игроков считаться из усреднения их фпс?
Ну и в 90-х, физика была попроще. От фпс мало зависело движение объектов.
а вот прыжок на t2 с лесенки на шарды (и в тысяче других подобных мест) действительно при фпс ниже 120 не удавался по высоте.
в 90-х, физика была попроще. От фпс мало зависело движение объектов
Нет, движок Quake при FPS выше ста начинал ощутимо глючить в расчётах физики позволяя использовать его багофичи для всяких сложных продвинутых трюков.
q3 вышла в декабре 99. Почти начало 2000-х.
Я не сравниваю современные игры с играми прошлых лет. justmara предположил, что зависимость физики от фпс видеокарты — полная дурь, но тем не менее, нечто подобное было.
зависимость физики от фпс видеокарты — полная дурь
А если физику считать через CUDA на видеокарте, тогда как?
зависимость физики от фпс видеокарты — полная дурь, но тем не менее, нечто подобное было.Было-было. В Mafia 1 даже непроходимые места из-за этого есть.
Just like with the Exploding Celeste mission, this subquest is virtually impossible if you own a better hardware which gives a good framerate. But lowering the framerate will reduce the rate of bombs dropping and thus, the probability of your car being hit.
Еще почитать: pcgamingwiki.com/wiki/Glossary:Frame_rate_(FPS)#Frame_rate_capping
Этот параметр называется tickrate. Он нужен для синхронизации состояний и к плавности картинки отношения не имеет. У недостаточного tickrate-а совершенно другие симптомы. Хороший пример это Battlefield 3 с его 10Hz на старте продаж. На YouTube думаю ещё остались видео с тем как это выглядело.
При этом считать движение с фиксированным dt будет немного проще.
А если CPU/GPU не успевает просчитать кадр, то повторять предыдущий, либо рендерить каждый кадр последовательными приближениями с лимитом на время выполнения.
Мне бы очень хотелось знать, что я могу сделать, как обычный геймер. Это чертовски актуально, т.к. есть вполне отличные игры, которые «какбы» выдают свои 60fps, однако при этом картинка совсем-совсем не плавная.
На данный момент мне немного помогало лишь отключение V-Sync и таким образом разблокировка fps выше 60. Но при этом, как побочный эффект (о котором честно предупреждает Nvidia) появляются всякие разрывы изображения.
Можно ещё что-то попробовать? Помогут ли всякие мотиторы с G-Sync & FreeSync?
Вообще, помнится, раньше нВидиа умела рендерить с отключенным vSync и без разрывов, но с тех пор она объелась стеройдов и положила качество в жертву скорости. Теоретически, *Sync-и должны помочь — сути их как раз в синхронизации времени вывода с временем рендеринга, так что попробовать можно.
Если fps падает ниже 30, G-Sync отключается, старые добрые лаги возвращаются.
Я уточняю, т.к. тут очень специфическая проблема, fps нормальный, с V-Sync всегда железно 60 кадров, ничего не проседает вообще. Однако именно картинка, которую видишь своими глазами, а не на датчиках, совсем не плавная.
Автор описал достаточно распространённую проблему, которая встречается много где, много у кого. Есть весьма неудачные в этом плане игры, которые страдают такой проблемой. У других же игр, на том же железе, таких проблем нет вообще.
Т.е. достаточно странная ситуация, учитывая, что автор говорит о том, что проблема в первую очередь на стороне производителей видеокарт и драйверов.
Если я правильно понял суть g-sync (что можем сами сказать монитору, что пора отображать новый кадр) — должен изрядно сгладить проблему. Мы просто не попадём в ситуацию, когда "отстали" (или решили, что отстали) аж на 1/60 или 1/120 секунды — можно же в этом случае просто отобразить кадр чуть-чуть позже.
Но полностью проблему (что для максимального fps нам надо заранее знать время обсчёта кадра) не уберёт.
G-sync так же проблему не решает! Проблема не в том, когда монитор отобразит отрендеренный кадр(этим занимается g-sync), но и что — для какого конкретно ближайшего будущего подготовленный кадр будет отображаться. Есть шанс в 50%(если успели до дедлайна) что монитор должен будет ждать дополнительные несколько миллисекунд, что бы начать поворачивать пиксели в точно расчитанное время, а не как быстрее. Это должно так же повысить плавность.
Не решает, а смягчает: допустим, мы обсчитывали кадр для момента t, но не успели на пару миллисекунд. С g-sync мы его (если я правильно понял суть технологии) сможем отобразить в момент t+2, без — только в t+16.6.
G-Sync & FreeSync помогут при нестабильных фреймтаймах и проседающего фпс — крайне полезная штука
В противном случае все объекты, которые передвигаются, будут двигаться со скоростью, зависящей от частоты кадров. В мультиплеере это вообще фиаско.
Можно даже использовать не целую секунду для расчетов, а последние 5-10 кадров, этого обычно достаточно для сглаживания пика. В зависимости от ситуации, среднее или медианное время последних N кадров может дать идеальный результат.
=>1/N * frame/frame * delta_time_1 => 1/N delta_time_1 = delta_time_n
То, что Вы предлагаете — это и есть подсчет времени, просто другое численное выражение( в долях от случайного временного интервала, а не в миллисекундах (тысячных долях от секунды).
Считается обычно для некоего разумного числа последних кадров N, потому как для 1 кадра смысла не имеет, для 1000 тоже. Значение 1/fps является средним значением длительности последних N кадров.
То, что я предлагаю (и что используется уже лет 15 в разных движках для некоторых задач, н-р, в Unigine), это использование плавающего усредненного времени кадра, либо медианного времени кадра, взятые для ближайшего временного интервала.
Грубо говоря рендер вначале берет каждую 0.1 секунду данные:
0.0, 0.1, 0.2, 0.3…
А потом у нас где-то возникли тормоза на полкадра и следующее чтение случилось когда натикало уже 0.45:
0.0, 0.1, 0.2, 0.3, 0.45…
При этом в реальности тормоза были только на CPU, а GPU вполне успешно продолжал работать и в «плановый» момент 0.5 затребовал новую информацию о состоянии мира. CPU в этот раз не протормозил и оперативно выдал запрошенное
0.0, 0.1, 0.2, 0.3, 0.45, 0.5,…
И все, приплыли, stutter. На экран в момент 0.4 будет показан кадр расчитанный для момента 0.45.
Так почти везде так и работает. Проблема из статьи — что-то специфичное для каких-то отдельных движков в отдельных играх.
Сама идея сперва синхронизировать стейт под фпс, а потом его обратно рассинхиронизировать отдает несколько альтернативной логикой :)
Вот где реальная проблема — это видео, т.к. там частота кадров фиксирована и без синхронизации нельзя.
Никто стейт не «рассинхронизирует» специально, статья про то что это явление само собой возникает из-за невозможности обеспечить стабильную задержку между определением состояния мира и выводом кадра на экран.
Так и работает это как? Выставлением равномерного шага симуляции от кадра к кадру при неравномерной частоте кадров?
Симуляции вообще ничего не надо знать о кадрах. Она просто работает по своему таймеру. А рендер время от времени выдает, с-но, кадры.
Проблемы возникнут только тогда, когда вы захотите обеспечить какую-то конкретную частоту кадров (например, сделаете ограничение в 60 фпс).
Проблема с-но естественным образом возникает из-за того что рендер забирает кадры с неравномерной задержкой (точнее не с той же самой задержкой с которой они показываются)
Это как раз не проблема. Забирает и забирает, фиг с ним, рывков от этого не возникнет.
Проблема начинается как раз тогда, когда вы попытаетесь синхронизировать частоту "забора", и для этого подкручиваете таймер самой симуляции. Эти ведь рывки из статьи — это не рывки отображения, это рывки симуляции. Видеокарта успевет рендерить равномерно, но сама симуляция из-за подкрутки становится неравномерной.
Если же вы не занимаетесь подкруткой таймера симуляции — то и рывков не будет, т.к. симуляция будет равномерной (если, конечно, она сама не начнет тормозить, но в реальности у нас практически все игры gpu-bound с огроменным запасом)
Забирает и забирает, фиг с ним, рывков от этого не возникнет.
Возникнет. Осознайте уже наконец что данные симуляции забираются рывками, неравномерно
Подкрутка симуляции которая так сбивает всех в данной статье — это просто способ не считать симуляцию в тех временных точках где она не нужна. Но проблема никак не связана с этой оптимизацией. Она будет возникать и при идеальной, непрерывной симуляции. Причем там дословно те же самые кадры с рывками будут забираться. Просто еще и куча «ненужных» будет выкидываться.
Возникнет. Осознайте уже наконец что данные симуляции забираются рывками, неравномерно
В рассматриваемом случае они забираются равномерно, но неравномерно происходит сама симуляция.
Подкрутка симуляции которая так сбивает всех в данной статье — это просто способ не считать симуляцию в тех временных точках где она не нужна. Но проблема никак не связана с этой оптимизацией.
Именно с ней она и связана. Из-за подкручивания таймера симуляция становится неравномерной — и когда вы равномерно выводите кадры неравномерной симуляции, то получаете рывки. Если не подкручивать кадры — проблемы просто нет.
Она будет возникать и при идеальной, непрерывной симуляции.
Откуда? Вы перечитайте еще раз пример с разбором из статьи. Кадр выводится за 16.5, но игра думает что он выведен за 24.8. При этом происходит подкрутка симуляции — и вместо того, чтобы через 16.5 сек вывести состояние через 16.5, выводится то состояние, в котором мир находится через 24.8. В результате симуляция мира опережает актуальное время, в которое выводится кадр, на 8.3, игра вам рендерит "будущее".
Если вы ничего не будете подкручивать, то через 16.5 игра выведет ровно то, что там и есть — состояние, в котором находится симуляция через 16.5.
При этом реальный фпс как раз 60 — именно об этом же и идет речь в статье, что фпс не падает, он держится ровно, кадры выводятся равномерно, но это не те кадры из-за того, что в силу подкрутки внутриигровое время симуляции скачкообразно опережает реальное.
В результате симуляция мира опережает актуальное время, в которое выводится кадр, на 8.3
Тут еще стоит добавить важный момент — сам рывок, что вы актуально видите, в большей степени связан не с этим опережающим кадром, а со следующим — когда происходит обратная синхронизация, и игра думает что получает кадр за 10.7
Если в первом случае вы испытываете "всего лишь" ускорение в 24.8/16.5 ~ 1.5 раза, то во втором кадре время замедляется, вы видите движение в 10.7 вместо 16.5, в итоге сравнительная скорость между двумя последовательными кадрами — 24.8/10.7 ~ 2.3.
В рассматриваемом случае они забираются равномерно, но неравномерно происходит сама симуляция.
Неверно. Забираются они неравномерно а симуляция просто подстраивается под этот неравномерный момент забора. Вот выводятся на экран результаты равномерно, но вывод на экран != момент забора данных
Если не подкручивать кадры — проблемы просто нет.
Совсем не подкручивать (грубо говоря забирать данные симуляции с равномерным интервалом) нельзя в силу того что симуляция так или иначе должна синхронизироваться с происходящим на экране, иначе у нас физика начнет зависеть от FPS (больше FPS — быстрее падают объекты и т.д.)
Кадр выводится за 16.5, но игра думает что он выведен за 24.8.
Она так думает потому что прошло 24.8 мс с момента последнего забора данных от симуляции. А не потому что ей так внезапно захотелось. Понимаете теперь? Мы выводим состояние в момент времени «24.8» потому что мы запросили его в момент времени «24.8».
Поэтому важно синхронизировать два таймера. Но корректных данных о тиках внешнего таймера нет.
Если модель имеет внутренний таймер не кратный 10 тикам то будут рывки.
Значит достаточно, чтобы внутренний таймер был кратен, или достаточно быстрым, чтобы рыки не были заметны. Например если будет рывок в 10 микросекунд то вряд ли он будет заметен.
А вот синхронизация на равный тики действительно решает проблему. Но только корректно померить тики видеокарты на данный момент нельзя
Как раз на экране рывок в 10 мс виден по статье.
10мкс в 1000 раз меньше
А вот синхронизация на равный тики действительно решает проблему. Но только корректно померить тики видеокарты на данный момент нельзя
Ну понятное дело, что идеальное решение иметь обратную связь. Но когда это будет…

Вот какую проблему решал и решил гугл.
Со стороны кажется, что рендер не поспевает и происходит адаптация под проседания fps.
Проблема в том, что по факту это не так. Это может быть не GC, а что угодно, просто наблюдаемый факт, что драйвер чем-то занимается после реального обновления. У меня это проявляется и на Linux и на Windows. Драйверам никто не запрещает это делать, по документации все четко, ничего не нарушается. Да и от GC никуда не деться, если не на swap его выполнять (когда как раз кадр завершили и логично почистить), на идущий следом glClear()? В общем кривота это все, знать реальное время отображения нужно, без этого никуда.
А разве мы не можем просто…
… считать физику независимо от отрисовки? То есть один поток считает физику (время вычислений на CPU отлично измеряется), а другой периодически у него забирает последнее актуальное состояние. Тогда эффекта опережения не может быть (во всяком случае по причине неверно рассчитанного dt).
На винде это как раз примерное время preemption для потоков foreground-процесса
Кстати у меня иногда проскакивает «статтер» и на правильном плавном видео, благо только 1 на весь ролик.
Интересненько (про видео), напомнило старые времена, когда принудительно выставляли на мониторе (CRT) частоту кадров, кратную частоте кадров видео. А позже ещё какие-то трюки были для просмотра 50Гц видео на 60Гц мониторе, я уж подзабыл.
У меня 2 раза, второй на обратном пути, почти незаметный.
Пример: каждый кадр вызывают glBufferData с разными размерами, вместо того, чтобы один раз вызвать glBufferData с запасом, и обновлять его через glBufferSubData.
Если же надо рендерить при плавающем fps, то проблема никуда не девается. Физика игры берёться не на текущий момент, а на текущее время+ время рендеринга кадра. И если gpu говорит что не успевает отрисовать за 16, и успела только за 24 то игра пытается компенсировать просадку fps нарисовав кадр в более далеком будущем. Но в реальности просадки fps нет и кадр опережает реальный мир.
Но это работает только пока вы успеваете рендерить кадр без просадки fps.
Всмысле? Ну вот просел FPS до 20, а мы все равно забираем инпут и обновляем физику с частотой 60 раз в секунду. Почему это не работает то?
Физика игры берёться не на текущий момент, а на текущее время+ время рендеринга кадра.
Зачем физику брать на момент + время рендеринга кадра? Почему просто не брать физику от фиксированного времени без всякого плюс время рендеринга кадра?
Если не учитывать время рендеринга то картинка будет запаздывать, по ощущениям будет похоже что игра тормозит.
Если не учитывать время рендеринга то картинка будет запаздывать, по ощущениям будет похоже что игра тормозит.Уверяю вас, вы не почувствуете, что игра тормозит даже если изображение будет запаздывать на 16мс. Но ок, допустим мы знаем, что мы хотим получать 60FPS, и что у пользователя практически всегда будут стабильные 60FPS. В этом случае мы можем делать константную поправку на 16мс вперед. А если вдруг у пользователя FPS просядет до 30 в какой-то момент, то ок, он получит маленькую задержку в 16мс, что не смертельно.
В статье описывается как раз другой случай, когда при стабильных 60FPS время, когда кадр реально появляется на экране сильно ёрзает, и за счет этого мы собственно и видим рывки.
Он появляется вовремя и стабильно, но игра думает что иногда FPS проседает(хотя это и не правда) и пытается адаптироваться под проседание fps путём измения константы времени кадра. Что в свою очередь приводит к опережению по времени
Когда же они ставили постоянные 60 FPS они по факту и делали это поправку константой в 16 мс и лаги переставали наблюдаться.
У бетезды в движках при падении ФПС замедляется игровой таймер, и ничего, никаких проблем это не вызывает.
Обновление же игрового мира при этом живёт своей жизнью.
Это одна из первых вещей с которыми сталкиваешься при разработке игры без привлечения готовых движков.
Вот кто бы объяснил, в чём дело, и как с этим бороться. Я уж и vsync переключал, и другие опции крутил…
Началось это после перехода на Win7 с XP, причём на неновых уже играх — Чистое небо, Borderlands, Bioshock. На том же железе (где-то тех же лет сборки, уже тогда он был далеко не топ, но для подобных игр хватало — даже Crysis на средних настройках шёл).
Поставил на отдельный диск обратно XP — там всё нормально, только памяти не всем играм хватает (некоторые моды на сталкер довольно требовательны). Не, ну я понимаю, что сама операционка сколько-то ресурсов отжирает, и видимо, семерка таки побольше чем XP. Хотя встречал утверждения, что наоборот — семерка оптимизированнее и всё такое, а десятка так вообще…
В статье говорится, что данная проблема автором была замечена еще в 2003 году, и до сих пор не решена (в процессе создания решения) и эту проблему создает не железо (в/карта), а софтовый стэк: ОС + graphics API + GPU driver
Так же, на ощущение лага очень сильно влияет инпут-лаг.
habr.com/post/308980
P.S. Отличная статья, было интересно почитать.
2. Эти странные люди зачем-то измеряют время рендеринга кадра, и уже из этой метрики выводят сначала актуальное 3d, а затем и пиксельное положение графического объекта.
Ибо только так можно добиться того, чтобы пиксельные координаты «забежали вперед», что у них и происходит (иного способа осуществить «связь» между framerate и положением объекта/сцены не просматривается).
Все их проблемы от неверного архитектурного решения. Так как они делают делать нельзя.
Правильно делается так — положение любого 3D-объекта, втч камеры должно быть функцией от переменной time. Переменная time предоставляется hardware, средствами os (но ни в коем случае не самопальными © «равномерно идущими» программными таймерами). Задача этой переменной time всегда предельно равномерно (хардварно) идти вперед, инкрементируя своё значение независимо от os, игры и графики.
Что произойдет в случае просадки FPS, неравномерного начала кадра (джиттеринга) или напротив, в случае увеличения FPS? А ничего. Переменная time как равномерно шла вперед, так и будет идти. Позиция (вначале 3D, а затем пиксельная) никогда неверно пересчитана не будет, так как положение отвязано от кадров, да и от прорисовки вообще.
Это и есть единственное гарантированное решение проблемы.
Нельзя время забора кадра привязывать на внешний таймер идущий с равными тиками, так как тогда в случае просадки FPS или не равномерности по времени рендринга будет следующее — кадры будут обсчитанны для равномерного вывода, а выводиться будут через неравномерные промежутки и итоговая картинка будет дёрганной.
Нельзя время забора кадра привязывать на внешний таймер идущий с равными тиками, так как тогда в случае просадки FPS или не равномерности по времени рендринга будет следующее — кадры будут обсчитанны для равномерного вывода, а выводиться будут через неравномерные промежутки и итоговая картинка будет дёрганной.
В случае просадки FPS итоговая картинка в любом случае будет дерганной, и это никак не исправить, кроме как покупкой новой видеокарты или оптимизацией алгоритма в целом. Если гпу не успевает все что надо обсчитать — оно не успевает и никакие способы синхронизации вам не помог абсолютно никак.
Предложенный же вариант синхронизации не то что не помогает обеспечить большую плавность картинки, но и вредит, усиливая рассинхрон при определенных паттернах скачков. Это не говоря уже об описанном в статье эффекте. Тут выше кто-то верно заметил — ребята остались в 90-х, продолжая, зачем-то, мерить время в фпсах вместо того, чтобы мерить его в миллисекундах. Закономерно собрали грабли и теперь героически преодолевают собственноручно созданные проблемы.
а, и да:
Нельзя время забора кадра привязывать на внешний таймер
Никто не говорит о привязке времени забор кадра к таймеру. По внешнему таймеру должна идти симуляция, а когда забирать кадр — должна решать сама видеокарта.
Так в этом и проблема, что видеокарта говорит рендеринг кадра занял 24 мс, давай физику на следующие 24 мс. А на самом деле рендеринг кадра занял меньше 16 мс. Сейчас нет физической возможности правильно узнать время на которое надо посчитать физику для отображения.
Так видеокарта не должна говорить никаких мс, она говорит: «дай мне _текущее состояние_». И ЦПУ его отдает.
> Сейчас нет физической возможности правильно узнать время на которое надо посчитать физику для отображения.
А и не надо ничего узнавать, надо просто считать состояние мира по внешнему таймеру, 300раз в секунду допустим, и все.
> Если FPS просел с 60 кадров на 59 то при адаптивном шаге под время рендринга кадра картинка останется практически плавной, а вот если оставить время тика физики постоянным то постепенно накопиться разница по времени между кадром и физикой, что приведёт к дерганности картинки.
С чего бы? Будет видеокарта в каждый момент n/59с опрашивать состояние мира и в (n+1)/59с выводить, откуда дерганья?
В случае расчётов по физики фиксированным тикам не совпадающим с частой забора будет слудующее. Допустим физику считают каждые 16 мс. А выводят каждые 17 мс.
Время физики 0 16 32 48 64… 224 240 256
Время графики 0 17 34 51… 238 255 272
Видно что чем больше времени пройдёт тем больше рассинхронизация и для синхронизации придётся в один кадр запихнуть два тика физики.
Главный вопрос что есть «текущее» состояние мира? Время прихода команды на начало рендринга кадра плавает от кадра к кадру. Например для первого кадра это было в 8 мс, для второго в 2 мс, а для третьего в 12 мс. Видеокарта успевает обсчитывать все и выдать кадр стабильно каждые 16 мс, даже если команда на начало немного запоздало, но при таком подходе картинка получается дёрганной.
Никто не будет считать физику 300 раз в секунду, это слишком нагружает CPU. Все считают физику по одному разу на каждый кадр без промежуточных состояний.
Это вы сейчас сами придумали, практически во всех играх без лоченого фпс снижением настроек можно добиться существенно больше 60фпс (в общем-то обычно до сотен фпс) и никакой синхронизации там нет — просто задача gpu-bound и считать состояние процессора чаще не проблема.
Видно что чем больше времени пройдёт тем больше рассинхронизация
С временем физики 0 16 32 48 64… 224 240 256
Вы как-то немного забываете о наличии монитора, которые выводит ровно кадр на 16мс хоть ты тресни (ну или не 16, но в любом случае с фиксированной частотой). Если ваша физика генерирует кадр в 16мс — это ровно столько сколько в состоянии вывести ваш монитор, и вам нету смысла ничего подкручивать под скорость карты, т.к. монитор один черт выводит с другой скоростью.
Если у вас включен всинк, вы в любом случае будете наблюдать дублированные кадры (когда карта не успела отдать монитору кадр за 16 мс), либо, при выключенном всинке — полосы на экране, когда монитор возьмет недорендеренное изображение с буфера.
и для синхронизации придётся в один кадр запихнуть два тика физики.
Нет, не придется. В какой-то момент (в данном случае это будет 272мс, в этот момент видеокарта затребует состояние, и это будет не состояние 256мс физики, а состояние 272мс физики, оно успеет пересчитаться) временные отметки сойдутся, при этом карта успеет отрендерить 16 кадров, а симуляция — сделать 17 тиков. Т.о., карта пропустит один тик (то, что 256мс). Ну и что? Пусть хоть миллион тиков пропустит — нам это не важно, главное чтобы совпадало время.
Главный вопрос что есть «текущее» состояние мира?
Это то, которое сейчас лежит в памяти.
Видеокарта успевает обсчитывать все и выдать кадр стабильно каждые 16 мс, даже если команда на начало немного запоздало, но при таком подходе картинка получается дёрганной.
Да нету никаких "запоздалых команд", видеокарта просто нонстопом рендерит новые кадры по окончанию рендера предыдущих, с оглядкой на монитор при включенном всинке.
Если она выдает вам стабильные 16фпс — будет у вас ровная картинка. Конечно, если вы не из горе оптимизаторов вроде автора статьи, умудрившихся своими "оптимизациями" сделать так, чтобы игра тормозила не только на, с-но, тормозящем железе, но и на топовых печах :)
Я в какой-то момент устал — некоторые комментаторы уж очень упорны в своей неправоте.
Я вообще сейчас все посчитал, и штука оказалось даже забавнее. Случай с физикой 16мс, 16мс монитор, 20мс рендер:
16 32 48 64 96 112
36 56 76 96 116 136
48 64 80 96 128 144
первая строка — мс на котором мы получаем результат физики, вторая — на котором результат отрендерен, третья — на котором он выводится на монитор.
Как видно, задержка стабильная по 32мс, то есть монитор выводит ровно со скоростью симуляции, при этом выпадает кадр на 112мс, видеокарта не успевает дать результат рендера и там дублируется предыдущий кадр. Т.о. получаем — кадры идут ровно с регулярными спайками по 2 кадра.
Теперь вариант с подкруткой физики под 20мс тики:
20 40 60 80 100 120
40 60 80 100 120 140
48 64 80 112 128 144
кадр на 96 выпадает аналогично предыдущему случаю, то есть будут присутствовать те же регулярные спайки, никакого чуда :)
но вот что интересно, задержки между результатом симуляции и выводом:
28 24 20 32 28 24
они ж, мать вашу, неравномерны :cry:
из-за некратности тиков симуляции и тиков монитора, натурально, кадры при выводе на монитор оказываются пропорционально ускорены. Но самое веселое вот этот участок: 20 32 28 — именно перед 32 у нас пропущенный кадр.
Так вот, вместо "ровный кадр — дубль — ровный кадр" в первом случае мы во втором, с подкруткой, имеем "ускоренный кадр — дубль — замедленный кадр (в полтора раза!) — ускоренный кадр".
Ежу понятно, что зрительно это будет значительно печальнее первого случая.
И вот в этом вот контексте у меня возникает закономерный вопрос — а то, что у них там "тормозит" — это действительно все из-за "видеокарты асинхронно блаблабла", или просто их "оптимизация" by-design кривая и все портит? :)
И это ведь еще не рассмотрен случай неравномерных тормозов, где рассихнрон пойдет вообще везде и всюду из-за того, что подстройка идет по таймингу предыдущего кадра (тайминг текущего мы не знаем — он же еще не отрендерен).
Как видно, с-но, синхра рендера с физикой ничего не дает, а вот синхра физики с монитором — весьма полезна. К счастью, для синхронизации физики с монитором никаких хитростей не надо — частота-то постоянная :)
Но разработчики также учитывают что машина пользователя может быть слабее и время рендринга может быть 20 мс. В таком случае надо поменять тик физики, иначе как вы выше написали будет неравномерно дрыгающая картинка. Для этого они спрашивают у видеокарты когда она закончила считать и вот тут возникают проблемы иногда видеокарта на этот вопрос отвечает полную чушь, несоответствующую действительности. А дальше начинаются визуальные лаги при том что все успевает обсчитаться.
Теперь вариант с подкруткой физики под 20мс тики:
Неверно. Если v-sync выключен (а это практически всегда так) то видеокарта не ждет момента начала отрисовки следующего кадра а выводит его немедленно по окончанию рендеринга. Переключение с кадра на кадр и может и будет происходить в середине отрисовки монитором очередного кадра, при этом рисуется верхняя часть от одного кадра а нижняя — от следующего (screen tearing). То есть реальная отрисовка идет
20 40 60 80 100 120
40 60 80 100 120 140
40 60 80 100 120 140
ну или
20 40 60 80 100 120
40 60 80 100 120 140
50 70 90 110 130 150
если дать 10 мс на задержку сигнала при передаче его в монитор
Если же включить v-sync, то он, что удивительное дело, начинает учитываться в рендере. Т.е. округляем время рендеринга вверх до целого числа кадров
20 48 80 112 144
48 80 112 144 176
58 90 122 154 186
Симуляция идет с равномерным шагом в 32 мс (2 кадра), никаких рывков и дублей. Просто у нас FPS теперь становится кратен частоте смены кадров. Это либо строго 60 fps либо сразу 30 (20, 15...) а 59 уже не будет.
Неверно. Если v-sync выключен (а это практически всегда так) то видеокарта не ждет момента начала отрисовки следующего кадра а выводит его немедленно по окончанию рендеринга.
Видеокарта не может ничего выводить, физически. Выводит монитор. И монитор выводит ровно столько кадров в секунду, сколько выводит — каждые 16мс в рассматриваемом случае. По-этому нижний ряд у вас будет всегда идти кратными 16мс шагами, и вы никак не можете на это повлиять. При этом не важно включен всинк или нет — монитор в любом случае выводит по 16мс, просто без всинка будут кадры с полосами и на мониторе будет сразу два состояния вместо одного, от чего лучше, конечно, не станет. В любом случае, почти все поголовно играют с включенным всинком (особенно в шутаны с высокой сенсой — без всинка при падении фпс они неиграбельны) — так что кейз без него обсуждать смысла нет.
Если же включить v-sync, то он, что удивительное дело, начинает учитываться в рендере.
Это либо строго 60 fps либо сразу 30 (20, 15...) а 59 уже не будет.
Да, в 90-х, до изобретения тройной буферизации, именно так все и происходило. Я смотрю, вы такой же контраморт, как и авторы статьи.
Неверно. Забираются они неравномерно а симуляция просто подстраивается под этот неравномерный момент забора.
Вы статью вообще читали? В рассматриваемом случае кадры забираются по факту равномерно (раз в 16мс), но из-за невозможности синхронизации — движок об этом не знает и начинает отдавать кадры как будто фпс скачет.
Совсем не подкручивать (грубо говоря забирать данные симуляции с равномерным интервалом) нельзя в силу того что симуляция так или иначе должна синхронизироваться с происходящим на экране, иначе у нас физика начнет зависеть от FPS
Чтобы фпс влиял на скорость таймера надо скорости привязать к фпс. Все можно продемонстрировать на примере вот этого куска текста из статьи:
Если один кадр занимает 1/60 секунды (16,67 мс), а персонаж бежит со скоростью 10 м/с, то в каждом кадре он перемещается на 1/6 метра. Но если кадр перестаёт занимать 1/60 секунды, а вместо этого внезапно начал занимать 1/30 секунды (33,33 мс), то надо начать перемещать персонажа на 1/3 метра (в два раза «быстрее») за кадр, чтобы на экране он продолжал двигаться с кажущейся постоянной скоростью.
Итак, авторы хотят, чтобы персонаж бежал со скоростью 10 м/с (заметьте в "скорость 10 м/с" ничего про кадры нет!). Как сделает здоровый человек? Заведет таймер и установить скорость персонажа 10 м/с (как и требуется) относительно этого таймера. Как делают горе-оптимизаторы (и вы в их числе)? Они зачем-то устанавливают скорость относительно фпс (ЗАЧЕМ? где там вообще что-то про фпс? какое отношение фпс имеет к скорости персонажа???), потом ВНЕЗАПНО оказывается, что при падении фпс и скорость, ыраженная в фпс, меняется. И вместо того, чтобы подумать об архитектуре решения, ребята просто подкручивают скорости (в тех самых фпсах).
Так вот, отвечая на ваше исходное замечание — если вы скорость меряете по абсолютному внешнему таймеру, без фпс, то ничего подкручивать не надо. И скорость при этом с изменением фпс меняться не будет, потому что фпс на нее просто тупо никак не влияет.
Она так думает потому что прошло 24.8 мс с момента последнего забора данных от симуляции.
Нет, с последнего забора прошло 16мс. Если бы с последнего забора прошло бы 24мс, то игра и кадр бы не смогла вывести раньше, чем через 24мс, тогда бы вы увидели сдублированный кадр (или недорендеренный, при выключенном всинке, но у них, понятное дело, всинк включен). А она новый кадр вывела вовремя. И он ровный!
Невозможно физически вывести на мониторе через 16мс новый полноценный кадр, если задержка перед забором была больше 16мс. Неужели это не очевидно?
Если же ваша карта запросила новый кадр на рендер через 24мс вместо 16мс — значит она тормозит и не способна выводить 60фпс. И, конечно, в этом случае будут артефакты, по-любому. Меньшие в том случае, если вы не осуществляете подкрутку симуляции и больше, в том — если осуществляете.
Чтобы знать на какое время считать следующий тик физики он спрашивает видеокарту сколько она рендерит кадр — драйвер отвечает 24 мс, но при этом успевает обсчитывать каждые 16 мс кадр.
Видеокарта не запрашивает кадр. Это cpu говорит ей вот начало нового кадра, физика обсчитана на такое то время.
Чтобы знать на какое время считать следующий тик физики он спрашивает видеокарту сколько она рендерит кадр — драйвер отвечает 24 мс, но при этом успевает обсчитывать каждые 16 мс кадр.
Ну вот у гореоптимизаторов так все и реализовано, что и приводит к проблемам. У нормальных людей видеокарта просто рендерит кадры по факту готовности.
Чтобы знать на какое время считать следующий тик физики он спрашивает видеокарту сколько она рендерит кадр — драйвер отвечает 24 мс, но при этом успевает обсчитывать каждые 16 мс кадр.
Вы понимаете, что в вашем описании работы гпу/цпу строго синхронна? гпу досчитала шаг — отдала цпу тайминг, цпу посчитал состояние — отдал гпу — гпу посчитала шаг…
При этом параллельно они работать не могут (т.к. цпу не может начать расчет состояния до того как ему придет тайминг, а гпу не может начать расчет до того, как будет завершен пересчет стейта), и вы добавите к затратам на рендер кадра видеокартой затраты на расчет стейта цпу. Одни проблемы.
Возвращаемся к исходному вопросу — зачем в принципе пытаться синхронизировать физику по фпс, если можно считать ее по отдельному таймеру и просто рендерить видеокартой по мере готовности?
Иначе как вы писали ниже будет постоянно повторяющаяся ситуация с неравномерностью видеоряда.
Ну и пусть будет. Какая разница, если его никто не видит?
В статье показаны отклонения на 10 мс и все замечают дерганность картинки.
В статье отклонения совсем другого характера, у нас же не о них речь.
Вариант «давайте делать симуляцию с шагом точно равным времени 1 кадра» который предлагает Druu выглядит рабочим и более простым и надежным чем вариант с подстройкой. Он правда не лишен полностью описываемой в статье проблемы, но все же более устойчив к ней чем вариант с подкруткой.
Видеокарта не может ничего выводить, физически.
Прекрасно может — в экранный буфер.
Выводит монитор. И монитор выводит ровно столько кадров в секунду, сколько выводит — каждые 16мс в рассматриваемом случае.
Тем не менее если в момент времени 24 мс сменить экранный буфер, то на многих (если не на всех) мониторах частично будет выведен новый кадр. А самые новые мониторы так вообще умеют адаптировать частоту смены кадров к моментам смены буфера. Эти реально подождут до 24 мс обновляться а не тупо заберут в 16 и 32
Чтобы фпс влиял на скорость таймера надо скорости привязать к фпс. :
Еще раз: есть два возможных варианта. Либо «подкрутки нет» и Вы просто генерируете равномерную последовательность состояний мира которая выводится на экран, но тогда все оказывается привязано к fps. Либо Вы начинаете генерировать последовательность НЕ равномерную (неважно как — контролируя ли размер шага или просто выбирая какое именно из состояний мира выбрать) и налетаете на проблему с тем что скорость выборки должна в точности совпадать со скоростью вывода на экран, что нередко нарушается.
Вы статью вообще читали? В рассматриваемом случае кадры забираются по факту равномерно (раз в 16мс)
Боюсь что это вы статью не читали (а точнее не поняли). Это выводятся кадры равномерно а вот забираются данные для них неравномерно.
Если же ваша карта запросила новый кадр на рендер через 24мс вместо 16мс — значит она тормозит и не способна выводить 60фпс
Вот Вы статью прочитали а ключевой момент в ней полностью проигнорировали. Момент когда «монитор запрашивает новый кадр» и момент когда исполняемый код запрашивает новый кадр это два разных момента времени и к сожалению интервал между ними не постоянен. Понимаете? Это два разных события и задержка между ними может варьироваться в широких пределах. Обычно она более-менее стабильна, но иногда из-за многопоточного характера обработки данных в момент когда CPU должен был бы запрашивать новое состояние мира он оказывается занят другими задачами и откладывает немедленное выполнение потока с запросом. Доделав ту другую задачу CPU начинает выполнение потока, поток запрашивает таймер, а по таймеру — внезапно — натикало уже 24 мс.
В любом случае, почти все поголовно играют с включенным всинком
Мгм, в мое время v-sync поголовно выключали. Может конечно я отстал от жизни…
тройной буферизации
В случае тройной буферизации идет точно такая же привязка физики к моменту vsync а не к моменту завершения вывода в буфер. Для этого графическому движку достаточно просто округлить определяемый по таймеру ожидаемый момент вывоба кадра вверх до целого числа кадров, только и всего. И движок из описываемого примера это, разумеется, умеет делать.
20 64 80 112 128 144 160 192 208 224 240 272
40 60 80 100 120 140 160 180 200 220 240 260
48 64 80 112 128 144 160 192 208 224 240 272
64 80 112 128 144 160 192 208 224 240 272 288
Первая строчка — момент запрошенный у физического движка
Вторая — момент завершения рендеринга в буфер
Третья — момент вывода буфера на экран
Четвертая (копируемая в первую) — расчетное время следующего вывода буфера на экран исходя из предыдущего опыта
Боюсь что это вы статью не читали (а точнее не поняли). Это выводятся кадры равномерно а вот забираются данные для них неравномерно.
Я понял что вы имеете в виду, но в вашем случае игра получает корректные тайминги, а авторы говорят о некорректных, указывая это вполне однозначно. По-этому я склонен полагать, что авторы говорят о другой проблеме (именно некорректных таймингах).
В рассматриваемом же вами случае (если я понял верно) первый кадр рендерим за 16мс, потом карта что-то делает (неизвестно что, но мало ли у нее может быть занятий?) в течении 8мс и, т.о. запрашивает следующий кадр через 24мс от предыдущего запроса (о чем и отчитывается, вполне корректно). При этом сам кадр она рендерит за 8мс (или меньше) и, тем самым, успевает к отметке в 32мс.
Но в такой постановке проблема не в какой-то непонятной асихнронности и не в ошибочных таймингах — а именно в том, что игра слишком быстро (выше ожиданий, на основе которых мы подкручивали симуляцию, когда увидели задержку в 24мс) отрендерила следующий кадр. И у нас нет ведь никакой возможности предсказать заранее, что она его отрендерит за 8мс или 16мс или 20мс или сколько угодно (т.к. это в будущем). То есть проблема в рамках рассматриваемого подхода становится неустранимой принципиально, и никакое дополнительное апи или еще там чего не поможет, разве нет?
16мс, 16мс монитор, 20мс рендер:
16 32 48 64 96 112
36 56 76 96 116 136
48 64 80 96 128 144
А чего дальше свой ряд не продлили? У вас получится дерганье каждый пятый кадр, потому что он будет дублироваться на мониторе. Либо скипаться, если рендеринг будет быстрее 16мс.
Ну и с чего вы взяли, что рендер всегда 20мс? Он каждый раз разный практически всегда.
А чего дальше свой ряд не продлили? У вас получится дерганье каждый пятый кадр
Потому и не продлил, что дальше все повторяется циклически. Дерганье каждый пятый кадр, да. Потому что видеокарта физически не может больше 4 кадров отрендерить и вы с этим ничего не сделаете.
В случае подкручивания физики — у вас то же самое дерганье.
Ну и с чего вы взяли, что рендер всегда 20мс? Он каждый раз разный практически всегда.
Когда он разный, то ситуация во втором случае еще хуже по сравнению с первой. То есть я взял идеальный для "алгоритма подкручивания" вариант и в нем все плохо.
При включённой g-sync/freesync каждые 20мс будет выдаваться плавный кадр без всяких дёрганий
Действительно, при включенном g-sync/freesync ситуация будет лучше, но… только до тех пор, пока условия остаются полностью идеальными (фпс постоянный). Как только они идеальными быть перестают (фпс начнет меняться хоть как-то) — подкрутка снова превращается в тыкву, т.к. у вас нет возможности синхронизировать состояние в текущем фрейме при условии параллельной работы гпу/цпу. Только через фрейм.
Если FPS меняется не сильно (например с 60 упало до 50) то скачек будет с 16 мс до 20 мс всего 4 мс. После одного фрейма cpu пересчитает длину тиков физики и все придёт в норму.
Ну то есть в лучшем случае все будет ровно так же как и с равномерным таймером без подкруток.
Вот и возникает вопрос — зачем нужны подкрутки, если в любой реальной ситуации они могут лишь ухудшить положение?
Нет. В этом случае всего один кадр запоздает на 4 мс, а для всех последующих физика и рендер будет синхронным до следующего скачка FPS.
Нет, будет сперва задержка, а потом кратное ускорение.
И это будет постоянно т.к. мы рассматриваем ситуация с немаксимальным фпс. То есть он, по факту, будет прыгать абсолютно каждый кадр.
Ну и да, это все в случае работающего гсинка/фрисинка, что редкость.
Если отследить и изменить тик физики до 20 то рендер и физика опять будут синхронны
Картинка никогда не будет синхронной и плавной, потому что фпс всегда будет прыгать, а в будущее заглянуть нельзя.
Да и fps прыгает только при значительной смене объектов рендера, например при смене локации в рамках же одной сцены он более-менее постоянен
Картинка может будет не идеально плавной, но хотя бы не настолько дерганной как в случае с фиксированным таймером.
В случае с таймером у вас дерганье не будет превышать дельты вашей симуляции. Учитывая уже упоминаемое gpu-bound, никто не мешает выполнять симуляцию значительно чаще, чем раз в 16мс, за счет чего и дерганье сведется к нулю.
Да и fps прыгает только при значительной смене объектов рендера
Да ну, фпс не прыгает только в одном случае — если он выше залоченого предела (60 например). То есть карта дает 80 (которые выводятся как 60) или карта дает 70 (которые как те же 60) — и, да, фпс не меняется :)
Но если он у вас ниже максимума, то обычно любое изменение сцены дает изменение фпс: шагнули, повернули камеру, какой-то непись вышел/вошел в зону рендеринга — ну то есть короче всегда, когда игрок что-то делает.
Учитывая уже упоминаемое gpu-bound, никто не мешает выполнять симуляцию значительно чаще
Мешает ограниченность CPU. Даже сейчас игры встречаются игры упирающиеся в CPU и не выдающие стабильные 60 fps именно из-за ограничений в процессоре. Для отсутствия же артефактов надо считать в разы больше.
Решение с плавующим таймером позволяет в разы снизить требования к cpu пользователя.
Мешает ограниченность CPU.
Но это исключения из правил, таких игр единицы — и в основном это скорее всякие стратегии, чем скуримы и крузисы. В редкой игре урезанием графена нельзя получить фпс под две сотни.
0 16 32 48 64 80
Получит следующие значения физики
0 15 30 45 60 80
Кадры выводятся равномерно, но вот разница по физике у них
15 15 15 15 20
Каждый пятый кадр будет на треть быстрее. Получим неравномерный видеоряд.
К тому же такие значения можно получить только на мощных компах на которых и так можно поставить фиксированный 60 FPS.
Каждый пятый кадр будет на треть быстрее. Получим неравномерный видеоряд.
Не важно, равномерный видеоряд или нет. Важно, видно это или нет :)
К тому же такие значения можно получить только на мощных компах на которых и так можно поставить фиксированный 60 FPS.
Но на этих компах как раз метод с подкручиванием тормозит, как видно из статьи :)
На мощных компах метод с подкручиванием тормозит только потому что комп прикидывается, что не успевает рендерить.
В случае подкручивания физики — у вас то же самое дерганье.
Ошибаетесь. Я уже приводил три (три, Карл!) возможных примера реализации с подкручиванием физики (double-buffer без vsync, double-buffer с vsync, triple-buffer с vsync) и ни в одном из них нет дергания.
Надо клин клином выбивать
Ps да фантазирую, но вдруг это и вправду поможет?
- 1080 * 60 строчко-кадров в секунду? Это ж какая нагрузка на ЦП будет, чтобы для 65000 кадров в секунду считать физику и прочие подготовительные вычисления (например, сортировка по глубине)?
- Rolling shutter ужасно выглядит. Не надо эту блевотину.
- Рисование кадра — это не просто рисование 1080 линий и все. Перед этим считаются карты теней, кубические карты (анахронизм, но все равно) и буферы всякой всячины. Это константная часть, которую вам надо будет считать в 1080 раз чаще.
В общем — плохая идея.
Ps.Вот бы сделать демо, как это выглядило бы в 2d, но у меня недостаточно знаний в графике для того чтобы это сделать пока, скажем просто двигающиеся линии по монитору под разными углами.
Pss. Физику можно не считать, только изменения в положении камеры.
А вы пробовали?
>если рендерить в случайном порядке, а не сверху вниз.
Сейчас железо очень сильно полагается на пространственную когерентность доступа к памяти. Если вы сделаете случайные порядок — начнутся проблемы с текстурными кэшами, которые станут просто бесполезны, и широкой шиной памяти.
>Физику можно не считать, только изменения в положении камеры
Т.е. если вы едете в машине (камера движется) — для вас все гладко. А если машина перед вами (камера неподвижна) — она будет рывками?
А если камера привязана к физике? Ведь персонаж/машина, где едет персонаж движутся по физике.
Рендер циклично повторяется по известному паттерну, который очень похож на рандомный. Возможно можно найти ещё более красивые алгоритмы. Как сложность — необходимо подбирать/расчитывать под каждое разрешение по отдельности. Главное приимущество — частота кадров всегда постоянная, всегда околонулевая задержка, а производительность влияет только на величину блюра(угол открытия выдержки) он может меняться от 0 градусов до нескольких сотен/тысяч градусов (где 360 — идеально плавная картинка), от кадра к кадру.
Ps я пробовал, выглядит эпично, но есть БОЛЬШИЕ проблемы с производительностью. Нужно здорово оптимизировать.
Ps прошу оценить, на сколько мой бред имеет смысл)
Вы с нетерпением ждали следующей части вашей любимой серии видеоигр для PC и она наконец вышла.
Если позволите, малость позанудствую. В оригинале сказано следующее:
You’ve been waiting for the next installment of your favorite PC game series for so long, and now it’s finally here.
Как мне кажется, лучше сказать не «видеоигр для PC», а, скажем, «видеоигр для ПК» или «компьютерных игр». Второй вариант несколько лучше, поскольку охватывает самые разные компьютерные ОС (Windows, macOS, Linux и др.).
Я в курсе, что PC — это производное от IBM PC compatible computer, но предпочитаю передавать эту аббревиатуру на русском языке, в зависимости от контекста, как компьютер, компьютерный, ПК или даже Windows (если из контекста понятно, что речь идет именно об этой ОС).
Неуловимая проблема тайминга кадров