Winding Trail project

 

Волосатые шрифты

Декабрь 4, 2005, 1:41
Автор:
Alena
Категория: Программист

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

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

В DirectX есть две встроенных возможности работы с текстом. Первый - это интерфейс ID3DXFont. Второй - это класс шрифтов CD3DFont, описанный в примерах.

ID3DXFont использует GDI и предоставляет возможности работы со шрифтами аналогичные тем, что есть в Windows. Тут тебе и перенос строк, и текст можно сделать наклонным, подчеркнутым, можно выводить юникодные символы. Его большим минусом является то, что он очень тормозной.

CD3DFont значительно быстрее, но он и попроще. Например, переносить строки он не умеет. Работу с какими-либо языками, кроме английского, там тоже опустили. Но, я думаю, ее можно добавить. Итак, я начала свои изыскания с него. Ему в параметры надо передать название .ttf шрифта и размер, которым будешь печатать. После чего он печатает все буквы шрифта в отдельную текстуру, размер которой зависит от запрошенного размера и запоминает параметры этого шрифта в своей внутренней структуре: расстояния между буквами и все такое. Выглядит это примерно так.

А дальше уже можно им попробовать что-либо вывести. Вот скриншот из примера. Кроме CD3DFont здесь еще показана возможность создавать трехмерные шрифты, но она мне не нужна.

Нравятся мне эти примеры, в них всегда все хорошо. В примере текст выведен на черном фоне и в нем отсутствует буква i. Намеренно это сделано или нет, я не знаю, но белый фон и i являются большими проблемами CD3DFont. А у нас как раз используется темный текст на светлом фоне.

Буквы по краям как будто волосатые, будто бы антиалиасинг не включен (это с ключом ANTIALIASED_QUALITY), каждый вывод буквы i сопровождается артефактом - небольшой черточкой под буквой. Ладно, все равно там нет форматирования и русский язык пришлось бы прикручивать, смотрю следующий.

ID3DXFont. Ему тоже надо передавать имя шрифта и размер, но, в отличие от CD3DFont, который печатает сначала весь алфавит, а потом уже его использует, ID3DXFont каждый раз при выводе текста печает этот самый текст в отдельную текстуру, а потом копирует на экран. В форумах советуют один раз напечатать то, что надо, запомнить, а потом сохраненное выводить на экран, а не делать печать каждый кадр, чтобы тормозило поменьше. Кроме того, я вычитала, что в летнем апдейте DirectX его сильно поменяли, и он не такой уж и тормозной стал. Но… Все та же волосатость (ключ ANTIALIASED_QUALITY включен).

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

У меня была идея, что, возможно ID3DXFont в качестве фонового цвета во время отрисовки использует цвет текущего контекста устройства. Я пробовала его поменять, результат тот же самый.

Причем что меня еще настораживает, при одинаковом размере шрифта, то, что мне рисует ID3DXFont, гораздо меньше чем то, что рисует текстовый редактор. Возможно, он масштабируется? Но почему - неясно…

И при увеличении все же просматриваются попытки антиалиасинга. Первое слово - это ID3DXFont, второе - текстовый редактор.

А как вообще другие люди с этим борются? Поискала примеры в Интернете. Нашла два. Они очень похожи, вот один из них, rt_Text. Трехмерный текст меня, опять же, не интересует.

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

И старые знакомые глюки вернулись. Вон она, черная полоска под i, вон она знакомая волосатость, которая особенно видна на букве ‘а’.

Еще я смотрела библиотеку Drunken Hyena для вывода шрифтов. Основное, на что он напирает в документации, это скорость вывода. Форматирования там, похоже, нет. Но я еще буду ее смотреть внимательнее.

Какие у меня еще есть варианты… Есть старый добрый способ, о котором я упоминала вначале: напечатать все буквы нужного .ttf шрифта в текстуру с помощью какой-нибудь тулзы и вырезать по буковке самостоятельно. Форматирование, значит, тоже самой делать.

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

Если у кого еще есть какие-нибудь предложения, поделитесь!


Комментариев: 12
Оставить комментарий
Автор: tensor (12.04.05, Декабрь 4, 2005, 12:41)

1) Во многих “больших” играх как раз свои, рисованные шрифты. Необязательно делать в 2^n x 2^m текстуру, можно рисовать “в полоску” (rgb битмап, например). Red-канал будет отвечать за границу букв (так как разная ширина) - просто однопиксельные полоски на границах букв. Green - за начертание буквы. Blue можно оставить для “эффектов” - антиалиасинг, emboss, shadow и т.д. (фактически, это либо размытый контур буквы, который был в green, либо аналогичный эффект).
При загрузке в программу получим не DX-текстуру, а некую структуру данных, где на каждую букву указана ее ширина и хранятся битовые данные контура буквы и (если надо очень) битовые данные маски (для эффектов тени, объемности и т.д.)
Минимально необходимое форматирование (разбивку длинного текста на строки заданной ширины, центрирование и т.д.) несложно сделать, зная GetFontHeight() (она известна) и GetTextLength() (легко считать, зная длину каждой буквы).
При выводе же текста в программе можно поступить так. Создать прямоугольную область размерами (GetTextWidth(), GetTextHeight()), создать текстуру размеров (2^n), где n>=max(GetTextWidth(), GetTextHeight())[Понятно, что текстуру можно заранее создать, зная те размеры текстовой области, которые возможны в данной игре]. Для прямоугольной области (это два треугольника по сути) текстурные координаты задавать как GetTextWidth()/n, GetTextHeight()/n. LockRect() для текстуры, записывать в нее биты для соответствующих букв (если надо, после умножения на маску эффектов). Потом Unlock() текстуры и вывод области с текстом.
Чем хорошо - тем, что одно начертание шрифта можно использовать как для вывода текста, например, в длинных диалогах (где особо эффекты не нужны), так и для вывода в меню-счетчике_жизней-и-т-д (где нужны красивые эффекты - emboss, shadow, например).
Хорошо и тем, что сглаживание автоматически получится.
Также этим способом легко разноцветные буквы сделать.
Еще плюс - не возникнет проблем с точками над буквами и т.д. (вы же сами рисуете все), если, конечно, не ошибетесь нигде.
Чем это отличается от просто текстуры? Да тем, что в “просто текстуре” каналы цвета используются уже по прямому назначению, а здесь есть возможность сгладить текст или создать эффект.

2)Почему не видно результатов антиалиасинга на картинках? Может, потому что полноценный антиалиасинг есть в GDI+, а вряд ли они его будут использовать, он менее быстрый чем GDI.

3)Странно, что при таком количестве игр (funnyarts) все еще не найдет приемлемый для вас способ работы с текстами и со шрифтами…

Автор: Alena (12.04.05, Декабрь 4, 2005, 13:42)

Минимально необходимое форматирование несложно сделать…

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

Но, в любом случае спасибо тебе. Очень может быть, что все изложенное мне очень пригодится…

3)Странно, что при таком количестве игр (funnyarts) все еще не найдет приемлемый для вас способ работы с текстами и со шрифтами…

Там форматирование не было нужно вообще.

Автор: Maniac (12.04.05, Декабрь 4, 2005, 14:20)

Насколько я знаю, в GDI с альясингом все нормально. Потому как он был еще аж в Windows 95 (с пакетом Microsoft Plus!) и волосатостью не страдал.

Вообще волосатость эта выглядит так, как будто черный контур сглаживают к серому фону, а не белому. Просто баг, по-моему…

Автор: tensor (12.04.05, Декабрь 4, 2005, 15:34)

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

в GDI с альясингом все нормально…еще аж в Windows 95 (с пакетом Microsoft Plus!) и волосатостью не страдал
Точно все? Для антиалиасинга шрифтов было в GDI ANTIALIASED_QUALITY (правда, с ограничениями). Но линии (у фигур) ведь плохо (совсем не) сглаживались.
В GDI+ просто еще метод добавили (и ограничений поменьше стало). И на линии тоже распространилось.

Автор: dustypup (12.04.05, Декабрь 4, 2005, 18:21)

ИМХО через текстуру единственный качественный вариант что в ДХ что в ОГЛ…

Автор: Dragula (12.05.05, Декабрь 5, 2005, 0:39)

Можно еще использовать FreeType: рендерить текст в текстуру c альфой, а потом ее уже на экран выводить. У NeHe для OGL был пример.

Автор: Alena (12.05.05, Декабрь 5, 2005, 19:57)

По итогам: я слегка переделала CD3DFont, он теперь хорошо отображает черные шрифты на белом фоне. Русские буквы я к CD3DFont не прикручивала еще. Артефактом рядом с буквой i оказался хвостик от буквы j. Тоже пока с этим ничего не делала, но для русского языка это все равно неактуально.
Пока я планирую CD3DFont использовать для крупных заголовков, а там, где нужно форматирование - ID3DXFont. Форматирование нужно большим объемам довольно-таки мелко написанного текста, на мелких шрифтах глюки незаметны.
Если эти мои планы окажутся удачными, напишу об этом поподробнее.

Автор: Tomaz (12.08.05, Декабрь 8, 2005, 10:50)

Я вчера специально проверил шрифты на “волосатость” в одной из игр, выпущенных Electronic Arts. Так вот, у них они тоже страдают этими атавизмами.

Автор: Atz (01.04.06, Январь 4, 2006, 1:30)

А сделайте шрифты как в “Больших Красных Гонках”. Они тампрыгабют:) и вообще, сумасшедшие такие… Очень интересно! Через несколько лет после появления этой игры такие шрифты использовали в программе “ОСП-студио” на ТВ. И опять же - это просто 2D процедурные текстуры.

Автор: Atz (01.04.06, Январь 4, 2006, 1:34)

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

Автор: Jim (01.04.06, Январь 4, 2006, 12:27)

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

Pingback Winding Trail project (02.16.07, Февраль 16, 2007, 21:22)

[…] Некоторое время назад у меня наблюдались проблемы со шрифтами. Сейчас мне удалось решить часть из них, а именно - сейчас я могу нормально вывести на экран неформатированный текст: крупные заголовки, пункты меню и тому подобное. Сделала я их таки с помощью стандартного CD3DFont, который переделала. Результат в целом хороший: […]



Оставить комментарий

(обязательно)

(обязательно)


Переводы строк автоматические, e-mail никогда не показывается, разрешен HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>