Как мы решаем большие требования к видеопамяти в 2D-игре?

Как мы решаем большие требования к видеопамяти в 2D-игре?


Мы разрабатываем 2D-игру (Factorio) в allegro C /C ++, и перед нами стоит проблема с увеличением требований к видеопамяти при увеличении игрового контента.

В настоящее время мы собираем всю информацию об изображениях, которые будут использоваться в первую очередь, обрезать все эти изображения как можно больше и максимально упорядочить их в больших атласах. Эти атласы хранятся в видеопамяти, размер которой зависит от системных ограничений; в настоящее время это обычно 2 изображения до 8192x8192, поэтому они требуют видеопамяти от 256 МБ до 512 МБ.

Эта система работает очень хорошо для нас, так как при некоторых пользовательских оптимизациях и разбиении потока рендеринга и обновления мы можем нарисовать десятки тысяч изображений на экране со скоростью 60 кадров в секунду; у нас есть много объектов на экране, и разрешение большого уменьшения является критическим требованием. Как мы хотели бы добавить еще, некоторые проблемы с требованиями к видеопамяти будут возникать, поэтому эта система не может быть удержана.

Одна из вещей, которую мы хотели попробовать, - иметь один атлас с наиболее распространенными изображениями, а второй - как кеш. Изображения будут перемещаться из растрового изображения памяти по требованию. С этим подходом существуют две проблемы:

  1. Рисунок из битовой карты памяти в видео растровое изображение мучительно медленный, в allegro.
  2. Невозможно работать с видеопотоком в другом, кроме основного потока, в allegro, поэтому он практически неприменим.

Вот некоторые дополнительные требования:

  • Игра должна быть детерминированной, поэтому проблемы производительности /времени загрузки никогда не могут изменить состояние игры.
  • Игра в реальном времени, и вскоре будет многопользовательская. Нам нужно избегать даже самого маленького заикания любой ценой.
  • Большая часть игры - это один непрерывный открытый мир.

Тест состоял из рисования 10 000 спрайтов в партии для размеров от 1x1 до 300x300, несколько раз для каждой конфигурации. Я провел тесты на Nvidia Geforce GTX 760.

  • Растровое изображение видеоизображения в видеоизображении в видеоизображении составляло 0.1us на спрайт, когда исходное растровое изображение не менялось между отдельными растровыми изображениями (вариант атласа); размер не имел значения
  • Растровое изображение видеоизображения к видеоизображению в битовой карте, в то время как исходная растровая карта была переключена между рисунками (вариант без атласа), заняла 0,56% на спрайт; размер тоже не имеет значения.
  • Растровое изображение памяти в графическом растровом изображении было действительно подозрительным. Размеры от 1x1 до 200x200 взяли 0,3 на битмап, поэтому не так ужасно медленно. Для больших размеров время начало резко расти, при 9us для 201x201 до 3116us для 291x291.

Использование атласа повышает производительность более чем на 5. Если у меня было 10 мс для рендеринга, с атласом я ограничусь 100 000 спрайтов на кадр, и без него - предел 20 000 спрайтов. Это будет проблематично.

Я также пытался найти способ протестировать сжатие растрового изображения и формат растрового изображения 1bpp для теней, но я не смог найти способ сделать это в аллегро.

40 голосов | спросил Marwin 12 PMpSat, 12 Apr 2014 21:21:29 +040021Saturday 2014, 21:21:29

6 ответов


17

У нас есть аналогичный случай с нашей RTS (KaM Remake). Все единицы и дома - спрайты. У нас есть 18 000 спрайтов для единиц и домов и местностей, плюс еще ~ 6 000 для командных цветов (применяется как маски). Длинные растяжки у нас также есть ~ 30 000 символов, используемых в шрифтах.

Итак, есть несколько оптимизаций для использования вами атласов RGBA32:

  • Разделите свой пул спрайтов на многие более мелкие атласы и используйте их по требованию, как описано в других ответах. Это также позволяет использовать различные методы оптимизации для каждого атласа индивидуально . Я подозреваю, что у вас будет немного меньше потраченного впустую ОЗУ, потому что при упаковке к таким огромным текстурам в нижней части обычно находятся неиспользуемые области;

  • Попробуйте использовать палитру текстур . Если вы используете шейдеры, вы можете «применить» палитру в коде шейдеров;

  • Вы можете изучить возможность использования RGB5_A1 вместо RGBA8 (если, например, тени шахматной доски подходят для вашей игры). Избегайте 8-битной альфы, когда это возможно, и используйте RGB5_A1 или эквивалентные форматы с меньшей точностью (как RGBA4), они занимают половину пространства;

  • Убедитесь, что вы плотно упаковываете спрайты в атласы (см. алгоритмы Bin Packing), вращайте спрайты, когда это необходимо, и посмотрите, можете ли вы перекрывать прозрачные углы для спрайтов rhombus;

  • Вы можете попробовать аппаратные форматы сжатия (DXT, S3TC и т. д.) - они могут значительно сократить использование ОЗУ, но проверить артефакты сжатия - на некоторых изображениях разница может быть незаметной ( вы можете использовать это выборочно, как описано в первой маркерной точке), но на некоторых - очень произносить. Различные форматы сжатия вызывают разные артефакты, поэтому вы можете выбрать тот, который лучше всего подходит для вашего художественного стиля.

  • Посмотрите на разделение больших спрайтов (конечно, не вручную, а внутри вашего атласного упаковщика текстуры) в статический фоновый спрайт и меньшие спрайты для анимированных частей.

ответил Kromster 25 AMpFri, 25 Apr 2014 08:38:16 +040038Friday 2014, 08:38:16
5

Прежде всего, вам нужно использовать более мелкие текстурные атласы. Чем меньше текстур у вас будет более сложным и жестким управлением памятью. Я бы предложил размер атласа 1024, в этом случае у вас было бы 128 текстур вместо 2 или 2048, в этом случае у вас было бы 32 текстуры, которые вы могли бы загрузить и выгрузить по мере необходимости.

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

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

Однако есть одна проблема, что происходит, когда что-то неожиданное произошло, что игра не была в состоянии предвидеть?

  • Паника и отображение экрана загрузки до загрузки всех необходимых материалов. Это может показаться разрушительным для этого опыта.
  • Имейте спрайты с низким разрешением для всех предустановленных, продолжая игру и заменяя их, как только спрайты с высоким разрешением заканчивают загрузку. Это может показаться дешевым для игрока.
  • Сделать это повлиять на игровой процесс и задержать событие столько, сколько необходимо. Например. не создавайте этого врага, пока он не загрузится. Не открывайте этот сундук с сокровищами до того, как будут загружены все графики для этой добычи и т. Д.
ответил API-Beast 24 PMpThu, 24 Apr 2014 16:43:03 +040043Thursday 2014, 16:43:03
2

Во-первых, найдите наиболее эффективный формат текстуры, который вы можете, пока все еще довольны визуальными эффектами игры, будь то RGBA4444 или сжатие DXT и т. д. Если вас не устраивают артефакты, сгенерированные в сжатом изображении в формате DXT, можно ли сделать изображения непрозрачными, используя сжатие DXT1 для цвета в сочетании с текстурой маскировки в оттенках серого размером 4 или 8 бит для альфы? Я предполагаю, что вы останетесь на RGBA8888 для графического интерфейса.

Я выступаю за то, чтобы разбить вещи на более мелкие текстуры, используя любой формат, который вы решили. Определите элементы, которые всегда находятся на экране и поэтому всегда загружаются, это могут быть аттракционы ландшафта и графического интерфейса. Затем я разбил оставшиеся предметы, которые обычно представляются вместе как можно больше. Я не думаю, что вы потеряете слишком много производительности, даже до 50-100 вызовов на ПК, но исправьте меня, если я ошибаюсь.

Следующим шагом будет создание версий mipmap этих текстур, как указано выше. Я не буду хранить их в одном файле, но отдельно. Таким образом, вы получите версии 1024x1024, 512x512, 256x256 и т. Д. Для каждого файла, и я сделаю это до тех пор, пока не достигню самого низкого уровня детализации, который я когда-либо захочет отображать.

Теперь, когда у вас есть отдельные текстуры, вы можете создать систему уровня детализации (LOD), которая загружает текстуры для текущего уровня масштабирования и выгружает текстуры, если не используется. Текстура не используется, если отображаемый элемент не находится на экране или не требуется текущим уровнем масштабирования. Попробуйте загрузить текстуры в видеопамять в потоке, отдельном для потоков обновления /рендеринга. Вы можете отображать самую низкую текстуру LOD до тех пор, пока не будет загружена требуемая. Иногда это может привести к видимому переключению между текстурой с низкой детализацией /высокой детализацией, но я полагаю, что это было бы только тогда, когда вы выполняете чрезвычайно быстрое масштабирование и перемещение по карте. Вы могли бы сделать систему интеллектуальной, пытаясь предварительно загрузить, где вы думаете, что человек будет перемещать или приближать и загружать как можно больше в пределах текущих ограничений памяти. Вы можете кэшировать, где был пользователь, пока они не уйдут.

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

ответил Christian 2 Mayam14 2014, 05:43:17
1

Я считаю, что лучший подход - разделить текстуру во многих файлах и загрузить их по требованию. Вероятно, ваша проблема в том, что вы пытаетесь загрузить большие текстуры, которые вам нужны для полной 3D-сцены, и для этого вы используете Allegro.

Для большого уменьшения масштаба, которое вы хотите применить, вы должны использовать mipmaps. Mipmaps - это версии ваших текстур с более низким разрешением, которые используются, когда объекты находятся достаточно далеко от камеры. Это означает, что вы можете сохранить свой 8192x8192 как 4096x4096, а затем еще один из 2048x2048 и т. Д., И вы переключаетесь на более низкие разрешения, чем меньше вы видите спрайт на экране. Вы можете сохранить их как отдельные текстуры или изменить их размер при загрузке (но генерация мип-карт во время выполнения увеличит время загрузки для вашей игры).

Правильная система управления загружает требуемые файлы по требованию и освобождает ресурсы, когда никто их не использует, а также другие вещи. Управление ресурсами - важная тема в разработке игр, и вы уменьшаете управление до простого сопоставления координат с одной текстурой, которая близка к отсутствию управления вообще.

ответил Pablo Ariel 13 AMpSun, 13 Apr 2014 02:11:55 +040011Sunday 2014, 02:11:55
1

Ничего себе, это огромное количество анимаций спрайтов, созданных из 3D-моделей, которые я предполагаю?

Вы действительно не должны делать эту игру в необработанном 2D. Когда у вас есть фиксированная перспектива, происходит забавная вещь, вы можете легко смешивать предварительно обработанные спрайты и фоны с живыми 3D-моделями, которые в значительной степени используются некоторыми играми. Если вы хотите, чтобы такая прекрасная анимация казалась самым естественным способом сделать это. Получите 3D-движок, настройте его на изометрическую перспективу и визуализируйте объекты, для которых вы продолжаете использовать спрайты, как простые плоские поверхности с изображением на них. И вы можете использовать сжатие текстур с помощью 3D-движка, что само по себе является большим шагом вперед.

Я не думаю, что загрузка и разгрузка сделают много для вас, поскольку вы можете иметь практически все на экране одновременно.

ответил aaaaaaaaaaaa 25 AMpFri, 25 Apr 2014 02:09:48 +040009Friday 2014, 02:09:48
0

Я рекомендую создавать больше атласных файлов, которые могут быть сжаты с помощью zlib и выгружены из сжатия для каждого атласа, а также имея больше файлов атласа и файлы меньшего размера, вы можете ограничить количество активных данных изображения в видеопамяти. Кроме того, реализуйте механизм тройного буфера, чтобы вы заранее подготовили каждый кадр рисования и имеете возможность закончить быстрее, чтобы заикания не появлялись на экране.

ответил Darxval 26 AMpSat, 26 Apr 2014 00:04:17 +040004Saturday 2014, 00:04:17

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132