С# или С++: много 16 цветных изображений загружаются в оперативную память. Эффективное решение?

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

Справочная информация:
- Все еще обсуждается, следует ли использовать С# (XNA) или С++. Мы не хотим делать это до тех пор, пока не выясним, как решить эту проблему на обоих языках.
- Использование максимальной памяти 256 МБ было бы здорово, если это возможно.
- Два символа будут присутствовать одновременно, и эти персонажи могут только переключаться между битвами. Есть время, чтобы загрузить/освободить память между битвами, но игра должна запускаться с постоянной 60 кадров в секунду во время боя. Каждый кадр составляет 16,67 мс
- Общее количество изображений на одного персонажа находится на низких сотнях. Каждое изображение составляет примерно 200x400 пикселей. В любой момент времени будет отображаться только одно изображение с каждого символа.

Без сжатия, каждое изображение занимает примерно 300 кбайт от моих вычислений; до 100 МБ для целого персонажа. Это слишком близко к пределу 256 МБ, учитывая, что для некоторых других ресурсов потребуется память.

Так как каждое изображение может быть сделано с общим количеством 16 цветов. Теоретически я должен был бы использовать 1/8-е пространство, если я могу воспользоваться этим. Я огляделся, но не нашел ни слова о том, что я поддерживаю палитру изображений. (Хранение каждого пикселя с использованием меньшего количества бит, каждый из которых соответствует 32-битовому цвету RGBa)

Мы попытались использовать сжатие DXT, однако артефакты сжатия довольно заметны.

Я рассматривал возможность создания собственного формата файла с 4 битами на пиксель (и дополнительной информацией о палитре), загрузкой всех изображений этого нового формата в ОЗУ до битвы, а затем при рисовании какого-либо определенного изображения распаковывать только это изображение в необработанное изображение, чтобы оно могло отображаться правильно. Я не знаю, реалистично ли выполнять так много операций присваивания (appx 200x400 для каждого символа = 160k) для каждого кадра. Это звучит очень хаки для меня.

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

Большое спасибо!

(Я также попытался использовать изображение только с одним каналом, а затем использовать шейдер для выполнения ряда операторов if для перевода различных значений в другие цвета. К сожалению, было слишком много строк кода для шейдера. также довольно хаки и плохо масштабируется.)

Ответ 1

Если вы хотите настроить таргетинг на XBox 360 и не иметь надлежащего (полномасштабного) devkit, тогда С# - ваш единственный вариант. Когда вы начинаете XNA, вы, конечно, делаете гораздо легче, особенно если вы сейчас просто делаете 2D (и заботитесь о многом другом, о котором вам не нужно беспокоиться прямо сейчас).

Что касается проблемы с ограничениями памяти, предложения по ее устранению:

  • Используйте формат текстуры 1555, чтобы уменьшить вдвое размер (хотя у вас будет только 1 бит альфа)
  • У разных изображений есть общие разделы? Не могли бы вы изобразить персонажа, используя несколько меньших фрагментов, а не один большой (т.е. Сетку 2х4 или более). Скорее всего, у вас будет много свободного места в углах, которые могут быть разделены между большинством изображений, и это даст хорошую экономию (я только заметил, что кто-то уже упоминал об этом через спрайты), хотя это должен быть вариант без потерь для сохранения память).
  • Вы уже упоминали, что пытаетесь подделать паллетированные текстуры. Вместо операторов IF вы можете иметь вторую текстуру, содержащую цвета палитры, и использовать значение, которое вы получаете от первой текстуры, в качестве координаты текстуры, чтобы искать вторую текстуру через пиксельный шейдер (вторая текстура - всего лишь 1D текстура 32-битных значений цвета).
  • Учитывая мощь современных процессоров и в зависимости от того, что еще вы делаете в то время, у вас вполне может быть достаточно ресурсов для распаковки кадров "на лету" для двух символов в текстуры, готовые к рендерингу (особенно с многоядерными). Вам нужно, по крайней мере, дважды буферизовать текстуры, чтобы остановить блокировку процессора, ожидая, пока графический процессор завершит использование их из предыдущего кадра.

Вы также можете объединить некоторые из этих параметров, чтобы сохранить больше.

Ответ 2

Используйте S3 Texture Compression (вместо DXTn). S3TC позволяет хранить текстуры со скоростью 4 бит/пиксель или 8 бит/пиксель, а также поддерживается графическими картами. Вам не нужно беспокоиться о том, чтобы разложить его на лету, поскольку это делает видеокарта.

DirectX имеет очень хорошую поддержку S3TC, как на С++, так и на С#.

Ответ 3

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

Я бы начал с С# и инфраструктуры XNA, так как есть превосходная поддержка встроенного процессора спрайтов, и конвейер контента может автоматически преобразовывать отдельные изображения в полный спрайт во время компиляции. Microsoft предоставляет пример проекта, демонстрирующий эту функциональность здесь: http://create.msdn.com/en-US/education/catalog/sample/sprite_sheet

Ответ 4

Вы можете использовать дерево кодирования Хаффмана для хранения данных, сжатых в памяти (поскольку, как вы говорите, он хорошо сжимается); затем извлечение/загрузка в режиме реального времени. Существуют и другие сжатые структуры данных, которые вы могли бы использовать.

Ответ 5

Вы можете посмотреть xnaMUGEN. Боевой игровой движок - это то, что можно легко сделать на С#.