Как нарисовать текст, используя только методы OpenGL? - PullRequest
36 голосов
/ 13 января 2012

У меня нет возможности использовать, кроме методов OpenGL (то есть glxxx() методы).Мне нужно рисовать текст, используя только методы gl.Прочитав красную книгу, я понимаю, что это возможно только методом glBitmap().Если это единственный возможный способ, то любой может помочь мне с информацией о массиве пикселей для всех символов.Есть ли другой способ рисовать текст?

Ответы [ 6 ]

52 голосов

Теория

Почему это сложно

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

image

Источник изображения .

Преобразование этих форматов в массивы пикселей (растеризация)слишком специфичен и выходит за рамки OpenGL, особенно потому, что OpenGl не имеет непрямых примитивов (например, см. Почему в OpenGL нет круговых или эллиптических примитивов? )

Самый простой подход заключается всначала растровые шрифты сами на процессоре, а затем передаем массив пикселей OpenGL в качестве текстуры.

Затем OpenGL знает, как очень хорошо справляться с массивами пикселей с помощью текстур.

Атлас текстуры

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

Чем эффективнееподход это растр всех символов, которые вы планируете использовать, и втиснуть их в одну текстуру.

А затем перенести это в графический процессор и использовать текстуру с пользовательскими координатами uv для выбора правильного символа.

Этот подход называется текстурным атласом , и его можно использовать не только для текстур, но и для других многократно используемых текстур, таких как плитки в 2D-играх или значки веб-интерфейса.

Википедиякартина полной текстуры, которая взята из freetype-gl, хорошо иллюстрирует это:

image

Я подозреваю, что оптимизация размещения персонажа для наименьшей проблемы с текстурой - сложная задача для NPсм.: Какой алгоритм можно использовать для упаковки прямоугольников разных размеров в наименьший из возможных прямоугольников довольно оптимальным способом?

Этот же метод используется в веб-разработке для передачи нескольких маленькихизображения (например, значки) сразу, но там это называется «CSS Sprites»: https://css -tricks.com / css-sprites / и используетсяd чтобы скрыть задержку в сети, а не задержку связи CPU / GPU.

Растровые методы без использования ЦП

Существуют также методы, которые не используют растр ЦП для текстур.

Растрирование ЦП является простым, поскольку оноиспользует GPU как можно меньше, но мы также начинаем думать, можно ли будет использовать эффективность GPU в дальнейшем.

Это видео FOSDEM 2014 объясняет другие существующие методы:

Шрифты внутри трехмерной геометрии с перспективой

Рендеринг шрифтов внутри трехмерной геометрии с перспективой (по сравнению с ортогональным HUD) намного сложнее, потому что перспектива может сделать одну часть символа намного ближе к экрану и больше, чем другая, делая униформуДискретизация процессора (например, растр, тесселяция) на закрытой части выглядит плохо.На самом деле это активная тема исследования:

enter image description here

Поля расстояний в настоящее время являются одним из популярных методов.

Реализации

Следующие примеры были протестированы на Ubuntu 15.10.

Поскольку это сложная проблема, как обсуждалось ранее, большинство примеров являются большими, и они взорвали бы предел в 30 КБ этого ответа, поэтому просто клонируйте соответствующие репозитории Git для компиляции.

Однако все они полностью с открытым исходным кодом, так что вы можете просто использовать RTFS.

Решения FreeType

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

Примеры / учебные пособия:

Другие растеризаторы шрифтов

Они кажутся менее хорошими, чем FreeType, но могут быть более легкими:

Пример учебника Антона по OpenGL 4 26 "Растровые шрифты"

Шрифт был создан автором вручную и сохранен в одном файле .png. Письма хранятся в виде массива внутри изображения.

Этот метод, конечно, не очень общий, и у вас возникнут трудности с интернационализацией.

Сборка с:

make -f Makefile.linux64

Предварительный просмотр:

enter image description here

Руководство по opengl, глава 11 "2D-шрифты"

Текстуры создаются из файлов DDS .

В учебном пособии объясняется, как создавались файлы DDS с использованием CBFG и Paint.Net .

.

Предварительный просмотр вывода:

enter image description here

По какой-то причине мне не хватает Сюзанны, но счетчик времени работает нормально: 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

enter image description here

Источник: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c

Живет в отдельном дереве для SDL и легко интегрируется.

Однако не предусмотрена реализация атласа текстуры, поэтому производительность будет ограничена: Как эффективно визуализировать шрифты и текст с помощью SDL2?

Похожие темы

8 голосов
/ 13 января 2012

enter image description here

Использование 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;
}
8 голосов
/ 13 января 2012

Рисование текста в обычном OpenGL не является прямой задачей. Возможно, вам следует взглянуть на библиотеки для этого (либо с помощью библиотеки, либо в качестве примера реализации).

Некоторые хорошие отправные точки могут быть GLFont , Обзор шрифтов OpenGL и Учебное пособие NeHe для растровых шрифтов (Windows) .

Обратите внимание, что растровые изображения - не единственный способ получения текста в OpenGL, как упоминалось в обзоре шрифтов.

6 голосов
/ 13 января 2012

В этой статье описывается, как отображать текст в OpenGL с использованием различных методов.

При использовании только opengl есть несколько способов:

  • с использованием glBitmap
  • с использованием текстур
  • с использованием списков отображения
2 голосов
/ 16 июля 2014

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

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

1 голос
/ 13 января 2012

Я думаю, что лучшее решение для рисования текста в OpenGL - это текстурные шрифты, я с ними работаю уже давно. Они гибкие, быстрые и красивые (за некоторыми исключениями). Я использую специальную программу для преобразования файлов шрифтов (например, .ttf) в текстуру, которая сохраняется в файл некоторого внутреннего формата «шрифта» (я разработал формат и программу на основе http://content.gpwiki.org/index.php/OpenGL:Tutorials:Font_System, хотя моя версия пошла довольно далеко от оригинальной поддержки Unicode и тд). При запуске основного приложения шрифты загружаются из этого «внутреннего» формата. Смотрите ссылку выше для получения дополнительной информации.

При таком подходе основное приложение не использует никаких специальных библиотек, таких как FreeType, что также нежелательно для меня. Текст рисуется с использованием стандартных функций OpenGL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...