Генерация растровых шрифтов в играх
Я использую растровые шрифты во всех своих играх. Это единственный метод отображения текста, который поддерживается моим движком, потому что он быстро обрабатывается видеокартой и требует мало памяти.
Растровые шрифты — это заранее нарисованный набор символов на текстуре, которая потом "режется" на кусочки для составления слов на экране.
Текстура, на которой рисуются все нужные символы, называется атласом.
Атлас обычно сопровождается текстовым файлом, в котором описана позиция и размер каждого символа, а также дополнительная информация о буквенных интервалах, кернинге, и других деталях.
Такой приём используется в компьютерах давно. Его относительно просто реализовать, и он хорошо вписывается в работу с видеокартой. Видеокарта получает от программы всего одну текстуру, которая хранится в памяти графического процессора, а для текстовых полей создаётся геометрия, которая обновляется только тогда, когда нужно поменять текст.
Таким образом можно быстро отображать большое количество динамического текста, и не надо задумываться о производительности.
Так как атлас — это просто картинка, то к буквам можно запросто добавить разные эффекты в графическом редакторе: тени, контуры, градиенты, и т.д. Такие эффекты никак не повлияют на производительность, потому что они "запекаются" в текстуре.
Однако, у такого подхода есть несколько больших минусов.
- Растровые шрифты плохо масштабируются. Для каждого размера шрифта нужно создать отдельный атлас.
- Можно использовать только те символы, которые есть в атласе. Если требуется добавить поддержку нового символа, то придётся обновлять все существующие атласы.
- В некоторых языках десятки тысяч символов. Для поддержки отдельных языков нужно создавать отдельные атласы, а также экономить место на текстуре — включать в атлас только те символы, которые действительно используются в игре.
Если, например, в игре используется 2 стиля шрифта, 5 размеров текста и поддерживается 3 языка, то выходит, что необходимо создать 30 атласов. Если вдруг понадобится добавить новый символ (например, ©), то надо будет обновлять все 30 атласов. Это число растёт с добавлением новых стилей, размеров и языков. Подготовка атласов может занять очень много времени.
Другой вариант — использовать векторные шрифты. Для таких нужен всего один исходный файл, в котором содержится векторная информация о всех символах. Для использования требуется некая библиотека, способная рисовать векторную графику на текстуру.
Но и здесь есть большие минусы:
- Рисовать векторные буквы — слишком медленно. Программа должна вычислить и отобразить каждый пиксель по формулам. Кроме того, это чаще всего происходит на процессоре.
- Каждый раз, когда нужно обновить текстовое поле, создаётся новая текстура, которая посылается на видеокарту для замены старой. Если текстовое поле обновляется каждый кадр, то Вы очень быстро столкнётесь с проблемами в производительности и использовании памяти.
Я хочу продолжать использовать растровые шрифты из-за их хорошей производительности, но я также хочу иметь гибкость и простоту использования векторных шрифтов, потому что мне не нравится вручную создавать атласы. Поэтому, для экономии времени и сил, я решил объединить два подхода в один.
Идея в том, что движок может использовать векторные шрифты, но только для автоматической генерации растровых шрифтов.
Игра загружает файл шрифта, читает его, использует векторную библиотеку для отображения каждого символа на текстуре, сохраняет в памяти информацию о позициях и буквенном кернинге — и растровый шрифт готов. Этот процесс повторяется для каждого стиля, размера и языка.
Весь внутренний код, который уже используется для отображения растровых шрифтов, остаётся неизменным. Следовательно, производительность не страдает. Но теперь вместо создания атласов вручную, я просто обновляю текстовые файлы для добавления поддержки новых стилей или языков.
Например, так выглядит файл, в котором описаны стили для английского языка:
{ "primary": { "glyphs": "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm!1234567890+-,.?!:()'\"#& ", "font": "PTSans-Regular.ttf" }, "secondary": { "glyphs": "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm!1234567890+-,.?!:()'\"#& ", "font": "PTSans-Italic.ttf" } }
Похожие файлы создаются для других языков.
В коде мне нужно только указать стиль и размер текстового поля, и движок автоматически создаёт нужный атлас. Если такой атлас уже был создан, то он берётся из памяти.
textField = BitmapTextField.fromStyle("primary", 24); textField.setText("As you value your life or your reason keep away from the moor");
Эта новая система будет использоваться в моей следующей игре. Файлы описания стилей, файлы шрифтов и переводов будут доступны в папке игры. Поэтому будет возможность создавать моды локализаций для официально неподдерживаемых языков.