У меня нет параметров для использования, кроме методов opengl (это методы glxxx()()). Мне нужно нарисовать текст, используя только методы gl. Прочитав красную книгу, я понимаю, что это возможно только через метод glBitmap(). Если это единственный возможный способ, то может ли кто-нибудь помочь мне с информацией о массиве пикселей для всех символов. Есть ли другой способ рисования текста?
Как нарисовать текст, используя только методы OpenGL?
Ответ 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
Связанные темы
Ответ 2
Используйте glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString)
.
Пример: ПРОСМОТР ЗВЕЗДНЫХ ВОЙН.
#include <windows.h>
#include <string.h>
#include <GL\glut.h>
#include <iostream.h>
#include <fstream.h>
GLfloat UpwardsScrollVelocity = -10.0;
float view=20.0;
char quote[6][80];
int numberOfQuotes=0,i;
//*********************************************
//* glutIdleFunc(timeTick); *
//*********************************************
void timeTick(void)
{
if (UpwardsScrollVelocity< -600)
view-=0.000011;
if(view < 0) {view=20; UpwardsScrollVelocity = -10.0;}
// exit(0);
UpwardsScrollVelocity -= 0.015;
glutPostRedisplay();
}
//*********************************************
//* printToConsoleWindow() *
//*********************************************
void printToConsoleWindow()
{
int l,lenghOfQuote, i;
for( l=0;l<numberOfQuotes;l++)
{
lenghOfQuote = (int)strlen(quote[l]);
for (i = 0; i < lenghOfQuote; i++)
{
//cout<<quote[l][i];
}
//out<<endl;
}
}
//*********************************************
//* RenderToDisplay() *
//*********************************************
void RenderToDisplay()
{
int l,lenghOfQuote, i;
glTranslatef(0.0, -100, UpwardsScrollVelocity);
glRotatef(-20, 1.0, 0.0, 0.0);
glScalef(0.1, 0.1, 0.1);
for( l=0;l<numberOfQuotes;l++)
{
lenghOfQuote = (int)strlen(quote[l]);
glPushMatrix();
glTranslatef(-(lenghOfQuote*37), -(l*200), 0.0);
for (i = 0; i < lenghOfQuote; i++)
{
glColor3f((UpwardsScrollVelocity/10)+300+(l*10),(UpwardsScrollVelocity/10)+300+(l*10),0.0);
glutStrokeCharacter(GLUT_STROKE_ROMAN, quote[l][i]);
}
glPopMatrix();
}
}
//*********************************************
//* glutDisplayFunc(myDisplayFunction); *
//*********************************************
void myDisplayFunction(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0, 30.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
RenderToDisplay();
glutSwapBuffers();
}
//*********************************************
//* glutReshapeFunc(reshape); *
//*********************************************
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1.0, 1.0, 3200);
glMatrixMode(GL_MODELVIEW);
}
//*********************************************
//* int main() *
//*********************************************
int main()
{
strcpy(quote[0],"Luke, I am your father!.");
strcpy(quote[1],"Obi-Wan has taught you well. ");
strcpy(quote[2],"The force is strong with this one. ");
strcpy(quote[3],"Alert all commands. Calculate every possible destination along their last known trajectory. ");
strcpy(quote[4],"The force is with you, young Skywalker, but you are not a Jedi yet.");
numberOfQuotes=5;
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 400);
glutCreateWindow("StarWars scroller");
glClearColor(0.0, 0.0, 0.0, 1.0);
glLineWidth(3);
glutDisplayFunc(myDisplayFunction);
glutReshapeFunc(reshape);
glutIdleFunc(timeTick);
glutMainLoop();
return 0;
}
Ответ 3
Рисование текста в простом OpenGL не является задачей с перенапряжением. Вероятно, вы должны взглянуть на библиотеки для этого (либо с помощью библиотеки, либо в качестве примера реализации).
Хорошими отправными точками могут быть GLFont, OpenGL Font Survey и Учебник NeHe для растровых шрифтов (Windows).
Обратите внимание, что растровые изображения - это не единственный способ получить текст в OpenGL, как указано в обзоре шрифтов.
Ответ 4
В этой статье описывается, как визуализировать текст в OpenGL, используя различные методы.
При использовании opengl существует несколько способов:
- с помощью glBitmap
- с использованием текстур
- с использованием списков отображения
Ответ 5
Загрузите изображение с символами в виде текстуры и нарисуйте часть этой текстуры в зависимости от того, какой символ вы хотите. Вы можете создать эту текстуру с помощью программы рисования, скопировать ее или использовать компонент окна для рисования на изображение и получить это изображение для точной копии системных шрифтов.
Не нужно использовать Glut или любое другое расширение, просто базовую работоспособность OpenGL. Он выполняет свою работу, не говоря уже о том, что это было сделано в течение десятилетий профессиональными программистами в очень успешных играх и других приложениях.
Ответ 6
Я думаю, что лучшим решением для рисования текста в OpenGL являются текстурные шрифты, я работаю с ними в течение длительного времени. Они гибкие, быстрые и приятные (с некоторыми задними исключениями). Я использую специальную программу для преобразования файлов шрифтов (например,.ttf) в текстуру, которая сохраняется в файле некоторого внутреннего формата шрифта (я разработал формат и программу на основе http://content.gpwiki.org/index.php/OpenGL:Tutorials:Font_System, хотя моя версия прошла довольно далеко от оригинала, поддерживающего Unicode и т.д.). При запуске основного приложения шрифты загружаются из этого "внутреннего" формата. Посмотрите ссылку выше для получения дополнительной информации.
При таком подходе основное приложение не использует никаких специальных библиотек, таких как FreeType, что нежелательно и для меня. Текст рисуется с использованием стандартных функций OpenGL.