font.md 22 KB


title: Ресурс Font

brief: В этом руководстве описаны особенности работы со шрифтами и способ их вывода на экран в играх.

Ресурс Font

Шрифты используются для визуализации текста в компонентах Label и GUI-нодах Text. Defold поддерживает несколько форматов файлов шрифтов:

  • TrueType
  • OpenType
  • BMFont

Шрифты, добавленные в проект, автоматически конвертируются в текстуру, которую Defold может визуализировать. Доступны два метода визуализации шрифтов, каждый из которых имеет свои преимущества и недостатки:

  • Bitmap
  • Distance field

Создание шрифта

Чтобы создать шрифт для использования в Defold, создайте новый файл Font, выбрав в меню File ▸ New..., затем Font. Можно также кликнуть ПКМ в нужном расположении в браузере ассетов и выбрать New... ▸ Font.

New font name

Присвойте новому файлу шрифта имя и кликните Ok. Новый файл шрифта откроется в редакторе.

New font

Перетащите необходимый шрифт в браузер Assets в подходящее для него расположение.

В свойстве Font укажите файл шрифта и, при необходимости, настройте остальные свойства.

Свойства

Font : Файл TTF, OTF или .fnt, используемый для генерирования данных о шрифте.

Material : Материал, используемый при рендеринге этого шрифта. Обязательно измените этот параметр в соответствии с выбранным типом шрифта --- Distance Field или Bitmap (подробнее см. ниже).

Output Format : Тип генерируемых данных о шрифте.

  • TYPE_BITMAP --- конвертирует импортированный файл OTF или TTF в текстуру, представляющую собой изображение шрифта, растровые данные которой используются для визуализации текстовых нод. Цветовые каналы используются для кодирования формы граней, контура и отбрасываемой тени. Для файлов .fnt исходная растровая текстура используется как есть.
  • TYPE_DISTANCE_FIELD --- импортированный шрифт конвертируется в текстуру, данные о пикселях которой представляют не экранные пиксели, а расстояния до границы шрифта. Подробности см. ниже.

Render Mode : Режим рендеринга глифов.

  • MODE_SINGLE_LAYER --- создает по одному четырехугольнику для каждого символа.
  • MODE_MULTI_LAYER --- создает отдельные четырехугольные формы для глифа, контура и теней соответственно. Слои отображаются в обратном порядке (back-to-front), что исключает вероятность загораживания одного символа другим, ранее отображенным, в случае когда контур шире, чем расстояние между глифами. Этот режим рендеринга также обеспечивает правильное смещение теней, задаваемое свойствами Shadow X/Y в ресурсе шрифта.

Size : Целевой размер глифов в пикселях.

Antialias : Сглаживание шрифта при запекании в целевое растровое изображение. Установите значение 0, если хотите получить чисто пиксельный (pixel perfect) рендеринг шрифта.

Alpha : Прозрачность глифа. 0.0--1.0, где 0.0 означает прозрачность, а 1.0 --- непрозрачность.

Outline Alpha : Прозрачность сгенерированного контура. 0.0--1.0.

Outline Width : Ширина сгенерированного контура в пикселях. Установите значение 0 чтобы убрать контур.

Shadow Alpha : Прозрачность сгенерированной тени. 0.0--1.0.

::: sidenote Поддержка теней обеспечивается встроенными шейдерами материала шрифта и работает как в однослойном, так и в многослойном режиме рендеринга. Если многослойный рендеринг шрифта или поддержка теней не нужны, лучше использовать более простой шейдер, такой как builtins/font-singlelayer.fp. :::

Shadow Blur : Для растровых шрифтов эта настройка указывает на то, сколько раз небольшое зерно размытия будет применено к каждому глифу шрифта. Для шрифтов типа Distance Field эта настройка эквивалентна фактической ширине размытия в пикселях.

Shadow X/Y : Горизонтальное и вертикальное смещение сгенерированной тени в пикселях. Этот параметр влияет на тень глифа, только если свойство Render Mode установлено в значение MODE_MULTI_LAYER.

Characters : Какие символы включать в шрифт. По умолчанию это поле содержит печатные ASCII символы (коды символов 32–126). Вы можете добавить или удалить символы из этого поля, чтобы включить больше или меньше символов в шрифт.

::: sidenote Печатные ASCII символы: space ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ :::

All Chars : Если отметить это свойство, все глифы, имеющиеся в исходном файле, будут включены в вывод.

Cache Width/Height : Ограничивает размер кэша растра глифов. Когда движок рендерит текст, он ищет глиф в кэше растра. Если его там нет, он будет добавлен в кэш перед рендерингом. Если кэш растра слишком мал, чтобы вместить все глифы, которые движок пытается отрендерить, возникает ошибка (ERROR:RENDER: Out of available cache cells! Consider increasing cache_width or cache_height for the font.).

При значении 0 размер кэша устанавливается автоматически.

Шрифты Distance Field

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

Distance field font

Обязательно измените свойство Material шрифта на builtins/fonts/font-df.material (или любой другой материал, который может обрабатывать данные карты расстояния) при создании шрифта, иначе при выводе шрифта на экран будет использоваться неподходящий шейдер.

Растровые шрифты BMFont

В дополнение к генерируемым растровым картам Defold поддерживает предварительно запеченные растровые шрифты формата "BMFont". Эти шрифты представляют собой PNG-изображение в виде страницы с глифами. Кроме того, файл .fnt содержит информацию о том, где на странице находится каждый глиф, а также информацию о размере и кернинге. (Следует учесть, что Defold не поддерживает XML-версию формата .fnt, который используется в Phaser и в некоторых других инструментах).

Эти типы шрифтов не обеспечивают повышения производительности по сравнению с растровыми шрифтами, генерируемыми из файлов TrueType или OpenType, но могут включать произвольную графику, расцветку и тени непосредственно в изображении.

Добавьте сгенерированные файлы .fnt и .png в проект Defold. Эти файлы должны находиться в одной папке. Создайте новый файл шрифта и задайте свойству Font файл типа .fnt. Убедитесь, что Output Format установлен в значение TYPE_BITMAP. Defold не будет генерировать растровое изображение, а будет использовать то, которое содержится в PNG.

::: sidenote Для создания BMFont следует воспользоваться инструментом для генерирования соответствующих файлов. Существует несколько вариантов:

  • Bitmap Font Generator --- только для Windows, предоставляется AngelCode.
  • Shoebox --- бесплатное приложение на базе Adobe Air для Windows и macOS.
  • Hiero --- инструмент с открытым исходным кодом на языке Java.
  • Glyph Designer --- коммерческий инструмент для macOS от 71 Squared.
  • bmGlyph --- коммерческий инструмент для macOS от Sovapps. :::

BMfont

Чтобы шрифт отображался корректно, не забудьте установить его свойство Material в builtins/fonts/font-fnt.material.

Артефакты и рекомендации

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

Шрифты Distance Field очень хорошо реагируют на масштабирование. С другой стороны, растровые шрифты, будучи просто пиксельными изображениями, будут увеличиваться в размере, поэтому пиксели будут расти при масштабировании шрифта, что приведет к появлению блочных артефактов, то есть угловатости. Ниже приведен образец шрифта размером 48 пикселей, увеличенный в 4 раза.

Fonts scaled up

При уменьшении масштаба растровые текстуры могут качественно и эффективно масштабироваться и сглаживаться средствами GPU. Растровый шрифт лучше сохраняет свой цвет, чем шрифт с картой расстояний. Вот масштаб того же образца шрифта размером 48 пикселей, уменьшенный до 1/5 размера:

Fonts scaled down

Шрифты Distance Field должны быть отрендерены до целевого размера, достаточно большого для хранения информации о расстояниях и возможности описать кривые глифов шрифта. Это тот же шрифт, что и выше, но размером 18 пикселей и увеличенный в 10 раз. Разумеется, этого слишком мало для кодирования форм этого шрифта:

Distance field artifacts

Если поддержка теней и контуров не требуется, установите соответствующие им значения альфа в 0. В противном случае данные о тенях и контурах все равно будут генерироваться, что приведет к излишнему потреблению памяти. Если вы не хотите использовать поддержку теней или контуров, установите соответствующие значения альфа в ноль. В противном случае данные о тенях и контурах всё равно будут генерироваться, занимая лишнюю память.

Кэш шрифта

Ресурс шрифта в Defold приводит к появлению двух вещей во время выполнения: текстуры и данных шрифта.

  • Данные о шрифте состоят из списка вхождений глифов, каждое из которых содержит некоторую базовую информацию о кернинге и растровые данные для этого глифа.
  • Текстура --- это внутреннее название "кэша текстуры глифа", используемого при рендеринге текста для определенного шрифта.

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

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

  • texture_size_recip.x --- обратная ширина кэша
  • texture_size_recip.y --- обратная высота кэша
  • texture_size_recip.z --- отношение ширины ячейки кэша к ширине кэша
  • texture_size_recip.w --- отношение высоты ячейки кэша к высоте кэша

Например, чтобы сгенерировать градиент в фрагментном шейдере, достаточно написать:

float horizontal_gradient = fract(var_texcoord0.y / texture_size_recip.w);

Подробнее об унифицированных шейдерных переменных см. В руководстве по шейдерам.

Генерация во время выполнения

Возможно использовать генерацию шрифтов типа SDF (Distance Field) во время выполнения при использовании шрифтов TrueType (.ttf).
Этот подход позволяет значительно уменьшить размер загрузки и потребление памяти во время выполнения в игре на Defold.
Небольшой недостаток — небольшая задержка при генерации каждого глифа во время выполнения.

Активируйте эту возможность, установив параметр font.runtime_generation в файле game.project.

::: sidenote Эта функция на данный момент является экспериментальной, но планируется использовать её в качестве основного рабочего процесса в будущем. :::

::: important Этот параметр влияет на все .ttf шрифты в проекте. :::

Предварительная генерация кэша глифов

Чтобы упростить использование шрифтов, генерируемых во время выполнения, поддерживается предварительная генерация кэша глифов.
Это означает, что шрифт сгенерирует глифы, указанные в поле Characters ресурса шрифта.

::: sidenote Если установлено свойство All Chars, предварительная генерация не будет выполняться, так как это противоречит цели — не генерировать все глифы сразу. :::

Скриптование шрифтов

Для шрифтов, генерируемых во время выполнения, можно добавлять и удалять подшрифты.
Это полезно, если один большой шрифт был разделён на несколько файлов по наборам символов (например, для CJK).

::: important Добавление подшрифта не приводит к автоматической загрузке или отображению всех глифов. :::

-- Добавить диапазон A-Z в .fontc
local font_hash = hash("/assets/fonts/roboto.fontc")
local ttf_hash = hash("/assets/fonts/Roboto/Roboto-Bold.ttf")
local codepoint_min = 0x00000041 -- A
local codepoint_max = 0x0000005A -- Z
font.add_source(font_hash, ttf_hash, codepoint_min, codepoint_max)
-- Удалить связанный ttf-ресурс
local font_hash = hash("/assets/fonts/roboto.fontc")
local ttf_hash = hash("/assets/fonts/Roboto/Roboto-Bold.ttf")
font.remove_source(font_hash, ttf_hash)

Чтобы загрузить глифы в шрифт, необходимо вызвать font.add_glyphs(). Это асинхронная операция, и после её завершения можно безопасно отображать сообщения, содержащие эти глифы.

local function add_glyph_callback(self, id, result, errmsg)
  if not result then
    print("Запрос " .. id .. " завершился с ошибкой:", errmsg)
  else
    msg.post(some_url, "show_dialog")
  end
end

-- Загрузить глифы в шрифт
local font_hash = hash("/assets/fonts/roboto.fontc")
local glyphs = "Some text to be shown!" -- для наилучшей производительности используйте список уникальных глифов
local request_id = font.add_glyphs(font_hash, ttf_hash, add_glyph_callback)

И, когда символы больше не нужны, можно освободить память:

-- Удалить глифы из памяти
local font_hash = hash("/assets/fonts/roboto.fontc")
font.remove_glyphs(font_hash, "Все символы из набора")