Ответ 1
Теория
Почему это сложно
Популярные форматы шрифтов, такие как TrueType и OpenType, представляют собой векторные контурные форматы: они используют кривые Безье для определения границы буквы.
Преобразование этих форматов в массивы пикселей (растеризация) слишком специфично и выходит за рамки OpenGL, особенно потому, что OpenGl не имеет нечетких примитивов (например, см. Почему нет круга или эллипс-примитив в OpenGL?
Самый простой способ - сначала создать растровые шрифты на CPU, а затем передать массив пикселей в OpenGL как текстуру.
OpenGL знает, как хорошо справляться с массивами пикселей через текстуры.
Атлас текстуры
Мы можем растрировать символы для каждого фрейма и повторно создавать текстуры, но это не очень эффективно, особенно если символы имеют фиксированный размер.
Более эффективный подход состоит в том, чтобы растрировать все персонажи, которые вы планируете использовать, и набивать их на одной текстуре.
И затем перенесите это на GPU один раз и используйте текстуру с пользовательскими координатами uv, чтобы выбрать правильный символ.
Этот подход называется https://en.wikipedia.org/wiki/Texture_atlas, и его можно использовать не только для текстур, но и для других повторно используемых текстур, таких как плитки в 2D-игра или веб-пользовательский интерфейс.
Википедия: картина полной текстуры, которая сама взята из freetype-gl, хорошо иллюстрирует это:
Я подозреваю, что оптимизация размещения символов для наименьшей проблемы текстуры - проблема NP-hard, см. Какой алгоритм можно использовать для упаковки прямоугольников разного размера в самый маленький прямоугольник, который возможен в довольно оптимальный способ?
Тот же метод используется в веб-разработке для передачи нескольких небольших изображений (например, значков) сразу, но там он называется "CSS Sprites": https://css-tricks.com/css-sprites/ и используются, чтобы скрыть латентность сети, а не связь между CPU/GPU.
Растровые методы без процессора
Существуют также методы, которые не используют растровый процессор для текстур.
Растрирование процессора просто, потому что он использует GPU как можно меньше, но мы также начинаем думать, можно ли еще больше использовать эффективность GPU.
Этот видеоролик FOSDEM 2014 https://youtu.be/LZis03DXWjE?t=886 объясняет другие существующие методы:
- tesselation: преобразование шрифта в крошечные треугольники. Тогда графический процессор действительно хорош для рисования треугольников. Недостатки:
- генерирует связку треугольников
- O (n log n) Расчет ЦП треугольников
- рассчитать кривые на шейдерах. В документе 2005 года Blinn-Loop этот метод был указан на карте. Недостаток: сложный. Смотрите: Разрешение независимого кубического безьего рисунка на GPU (Blinn/Loop)
- прямые аппаратные реализации, такие как OpenVG https://en.wikipedia.org/wiki/OpenVG. Недостаток: по какой-то причине не очень широко внедрен. Видеть:
Шрифты внутри 3D-геометрии с перспективой
Рендеринг шрифтов внутри 3D-геометрии с перспективой (по сравнению с ортогональным HUD) намного сложнее, потому что перспектива может сделать одну часть персонажа намного ближе к экрану и больше, чем другую, делая равномерную дискретизацию процессора ( например растра, тесселяция) выглядят плохо на закрытой части. Это фактически активная тема исследования:
- Что представляет собой современное состояние для текстового рендеринга в OpenGL с версии 4.1?
- http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
Поле расстояний является одним из популярных методов.
Реализация
Следующие примеры были протестированы на Ubuntu 15.10.
Поскольку это сложная проблема, как обсуждалось ранее, большинство примеров являются большими и будут взорвать предел 30k char этого ответа, поэтому просто клонируйте соответствующие репозитории Git для компиляции.
Однако все они полностью открыты, поэтому вы можете просто RTFS.
Решения FreeType
FreeTypeвыглядит как доминирующая библиотека растеризации шрифтов с открытым исходным кодом, поэтому она позволит нам использовать шрифты TrueType и OpenType, что делает его самым элегантным решением.
-
https://github.com/rougier/freetype-gl
Был набор примеров OpenGL и freetype, но более или менее развивается в библиотеку, которая делает это, и предоставляет достойный API.
В любом случае уже можно было бы интегрировать его в свой проект, скопировав несколько исходных кодов.
Он предоставляет как текстурный атлас, так и методы полевого поля из коробки.
Демонстрации под: https://github.com/rougier/freetype-gl/tree/master/demos
Не имеет пакета Debian, и это боль для компиляции на Ubuntu 15.10: https://github.com/rougier/freetype-gl/issues/82#issuecomment-216025527 (проблемы с упаковкой, некоторые вверх по течению), но он стал лучше с 16.10.
Не имеет хорошего метода установки: https://github.com/rougier/freetype-gl/issues/115
Создает прекрасные выходные данные, такие как эта демонстрация:
-
libdgx https://github.com/libgdx/libgdx/tree/1.9.2/extensions/gdx-freetype
Примеры/учебники:
- учебник NEHE: http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/
- http://learnopengl.com/#!In-Practice/Text-Rendering упоминает об этом, но я не смог найти исполняемый исходный код
- Вопросы SO:
Другие растеризаторы шрифтов
Те кажутся менее хорошими, чем FreeType, но могут быть более легкими:
- https://github.com/nothings/stb/blob/master/stb_truetype.h
- http://www.angelcode.com/products/bmfont/
Антон OpenGL 4 Учебник пример 26 "Растровые шрифты"
- учебник: http://antongerdelan.net/opengl/)
- источник: https://github.com/capnramses/antons_opengl_tutorials_book/blob/9a117a649ae4d21d68d2b75af5232021f5957aac/26_bitmap_fonts/main.cpp
Шрифт был создан автором вручную и сохранен в одном файле .png
. Буквы хранятся в форме массива внутри изображения.
Этот метод, конечно, не очень общий, и у вас возникнут трудности с интернационализацией.
Построить с помощью:
make -f Makefile.linux64
Предварительный просмотр вывода:
opengl-tutorial глава 11 "2D-шрифты"
- учебник: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-11-2d-text/
- источник: https://github.com/opengl-tutorials/ogl/blob/71cad106cefef671907ba7791b28b19fa2cc034d/tutorial11_2d_fonts/tutorial11.cpp
Текстуры генерируются из файлов DDS.
В учебном пособии объясняется, как были созданы файлы DDS, используя CBFG и Paint.Net.
Предварительный просмотр вывода:
По какой-то причине Suzanne отсутствует для меня, но счетчик времени отлично работает: https://github.com/opengl-tutorials/ogl/issues/15
FreeGLUT
GLUT имеет glutStrokeCharacter
, а FreeGLUT - с открытым исходным кодом...
https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255
OpenGLText
https://github.com/tlorach/OpenGLText
Растровое изображение TrueType. Сотрудник NVIDIA. Цели для повторного использования. Еще не пробовал.
Пример ARM Mali GLES SDK
http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/, кажется, кодирует все символы в PNG и сокращает их оттуда.
SDL_ttf
Источник: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c
Живет в отдельном дереве SDL и легко интегрируется.
Не обеспечивает реализацию текстурного атласа, поэтому производительность будет ограничена: Эффективно рендеринг шрифтов и текста с помощью SDL2
Связанные темы