OpenGL - «ультрагладкая» анимация простого горизонтально движущегося объекта - PullRequest
7 голосов
/ 23 февраля 2012

Я просто хочу сделать простую анимацию (например, в C ++ с использованием OpenGL) некоторого движущегося объекта - скажем, простое горизонтальное перемещение квадрата слева направо.

В OpenGL я могу использовать "метод двойной буферизации и, скажем, пользователь (запускающий мое приложение с анимацией) включил «вертикальную синхронизацию» - так что я могу вызывать некоторую функцию каждый раз, когда обновляется монитор (я могу добиться этого, например, используя Qt toolkit иего функция "swapBuffers").

Итак, я думаю, что "самая плавная" анимация, которую я могу добиться, - это "перемещать квадрат, например, на 1 пиксель (могут быть другие значения) при каждом обновлении монитора").таким образом, в каждом «кадре» квадрат находится на 1 пиксель дальше - «Я это проверил, и он наверняка работает мягко».

Но проблема возникает, когда я хочу иметь «отдельный» поток для «игровой логики»"(перемещение квадрата на 1 пиксель вправо) и для" анимации "(отображение текущей позиции квадрата на экране).Например, игровой логический поток представляет собой цикл while, в котором я перемещаю квадрат на 1 пиксель, а затем «сплю» в течение некоторого времени, например 10 миллисекунд, и мой монитор обновляется, например, каждые 16 миллисекунд - движение квадрата"не будет на 100% гладким", потому что иногда монитор обновляется два раза, когда квадрат перемещается только на 1 пиксель, а не на 2 пикселя (потому что есть две "разные" частоты монитора и игровой логической цепочки) - и движениебудет выглядеть «немного вяло».

Итак, логично, я мог бы остаться с первым супер гладким методом, но его нельзя использовать, например, в многопользовательских (например, «сервер-клиент») играх -потому что разные компьютеры имеют разные частоты монитора (поэтому я должен использовать разные потоки для игровой логики (на сервере) и для анимации (на клиентах)).

Поэтому мой вопрос: есть некоторый метод, использующий разные потоки для игровой логики и анимации, которые делают "100% плавную" анимациюНапример, если движущийся объект существует, пожалуйста, опишите его здесь, или когда у меня просто была какая-то «более сложная сцена для рендеринга», я бы просто не увидел то «маленькое резкое движение», которое я вижу сейчас, когда я двигаю какой-то простой квадрат горизонтальнои я на этом глубоко концентрируюсь :)?

Ответы [ 2 ]

6 голосов
/ 23 февраля 2012

Ну, на самом деле это типичное поведение отдельного игрового цикла.Вы управляете всеми действиями, связанными с физикой (движением), в одном потоке, позволяя потоку рендеринга выполнять свою работу.Это на самом деле желательно.

Не забывайте, что этот способ реализации игрового цикла заключается в том, чтобы иметь максимально доступную частоту кадров при сохранении постоянной скорости физики.При более высоком FPS вы не можете увидеть этот эффект случайно, если нет никаких других проблем, связанных с кодом.Например, некоторая связь между частотой кадров и физикой.

Если вы хотите добиться того, что вы описываете как идеальную плавность, вы можете синхронизировать физический движок с VSync.Просто делайте всю свою физику ДО обновления, а потом ждите другого.

Но все это относится к объектам с постоянной скоростью.Если у вас есть объект с динамической скоростью, вы никогда не сможете узнать, когда нарисовать его, чтобы он был «синхронизирован».Та же проблема возникает тогда, когда вам нужно несколько объектов с разными постоянными скоростями.

Кроме того, это НЕ то, что вы хотите в сложных сценах.Вся идея V-sync состоит в том, чтобы ограничить эффект разрыва экрана.Вы определенно НЕ должны подключать свою физику или код рендеринга для отображения частоты обновления.Вы хотите, чтобы физический код выполнялся независимо от частоты обновления дисплея.Это может быть НАСТОЯЩАЯ боль в многопользовательских играх, например.Для начала посмотрите на эту страницу: Как работает игровой цикл

РЕДАКТИРОВАТЬ: Я говорю, что ваше видение идеальной плавности нереально.Вы можете замаскировать это с помощью техник, которые написал Кевин.Но вы всегда будете бороться с лимитами HW, такими как частота обновления или пикселизация дисплея.Например, у вас есть окно размером 640x480 пикселей.Теперь вы хотите, чтобы ваш объект двигался горизонтально.Вы можете переместить ваш объект, направляя вектор в направлении правого нижнего угла, НО вы должны увеличивать координаты объекта на число с плавающей точкой (640/480).Но при рендеринге вы переходите к целым числам.Таким образом, ваш объект движется неровно.Обойти это невозможно.На небольшой скорости вы можете это заметить.Вы можете размыть его или заставить его двигаться быстрее, но никогда от него не избавитесь ...

5 голосов
/ 23 февраля 2012
  1. Позвольте вашему объекту двигаться на доли пикселя.В OpenGL это можно сделать для вашего примера квадрата, нарисовав квадрат на текстуре (то есть на границе в один пиксель или больше), а не просто в качестве края многоугольника.Если вы визуализируете 2D-спрайт-графику, то вы получите это в значительной степени автоматически (но если у вас пиксельная графика 1: 1, она будет размытой / резкой / размытой при пересечении границ пикселей).

  2. Сглаживание (сглаживание) края многоугольника (GL_POLYGON_SMOOTH).Проблема этого метода в том, что он не работает с рендерингом на основе Z-буфера, поскольку он вызывает прозрачность, но если вы делаете 2D-сцену, вы всегда можете рисовать задом наперед.

  3. Включение сглаживания мультисэмпла / суперсэмпла, которое дороже, но не имеет вышеуказанной проблемы.

  4. Придайте вашему объекту достаточно анимированный вид, чтобы пиксельные сдвиги не возникали.Легко заметить, потому что на этом краю происходит гораздо больше (то есть он сам движется на месте со скоростью, превышающей 1 пиксель / кадр).

  5. Сделайте вашу игру достаточно сложной изавораживает, что игроки отвлекаются от просмотра пикселей.:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...