Нарисуйте текст в OpenGL ES
В настоящее время я разрабатываю небольшую игру OpenGL для платформы Android, и мне интересно, есть ли простой способ визуализации текста поверх визуализированного фрейма (например, HUD с оценкой игрока и т.д.). В тексте также должен быть использован пользовательский шрифт.
Я видел пример с использованием представления в качестве наложения, но я не знаю, хочу ли я это сделать, потому что позже я захочу портировать игру на другие платформы.
Любые идеи?
Ответы
Ответ 1
В Android SDK нет простого способа рисования текста в представлениях OpenGL. Оставляя вас со следующими параметрами.
- Поместите TextView поверх SurfaceView. Это медленный и плохой, но самый прямой подход.
- Оказывать общие строки текстур и просто рисовать эти текстуры. Это, безусловно, самый простой и быстрый, но наименее гибкий.
- Создайте собственный код рендеринга текста на основе спрайта. Вероятно, второй лучший выбор, если 2 не является вариантом. Хороший способ получить ваши ноги мокрые, но обратите внимание, что, хотя кажется простым (и основные функции), становится все сложнее и сложнее, поскольку вы добавляете дополнительные функции (выравнивание текстур, работа с разрывами строк, шрифты с переменной шириной и т.д.). ) - если вы воспользуетесь этим путем, сделайте это как можно проще, чем вы можете сойти с рук!
- Используйте встроенную библиотеку с открытым исходным кодом. Есть несколько сторон, если вы охотитесь на Google, сложный бит интегрирует их и работает. Но, по крайней мере, как только вы это сделаете, у вас будет все гибкость и зрелость, которые они предоставляют.
Ответ 2
Рендеринг текста в текстуру проще, чем то, что делает демоверсия Sprite Text, похоже, основная идея состоит в том, чтобы использовать класс Canvas для рендеринга в Bitmap, а затем передать Bitmap текстуре OpenGL:
// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap
// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);
//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
Ответ 3
Я написал учебник, который расширяет ответ, отправленный JVitela. В принципе, он использует ту же идею, но вместо того, чтобы преобразовывать каждую строку в текстуру, он отображает все символы из файла шрифта в текстуру и использует это для полного воспроизведения динамического текста без дальнейшего замедления (после завершения инициализации).
Основным преимуществом моего метода, по сравнению с различными генераторами шрифтов шрифтов, является то, что вы можете отправлять небольшие файлы шрифтов (.ttf.otf) с помощью своего проекта вместо того, чтобы отправлять большие растровые изображения для каждого изменения и размера шрифта. Он может генерировать идеальные качественные шрифты при любом разрешении, используя только файл шрифта:)
учебник содержит полный код, который можно использовать в любом проекте:)
Ответ 4
Взгляните на CBFG и порт Android для кода загрузки/рендеринга. Вы должны убрать код в свой проект и использовать его сразу.
CBFG - http://www.codehead.co.uk/cbfg
Android-загрузчик - http://www.codehead.co.uk/cbfg/TexFont.java
Ответ 5
Согласно этой ссылке:
http://code.neenbedankt.com/how-to-render-an-android-view-to-a-bitmap
Вы можете отобразить любой вид в растровое изображение. Возможно, стоит предположить, что вы можете компоновать представление по мере необходимости (включая текст, изображения и т.д.), А затем отобразить его в растровое изображение.
Используя код JVitela выше, вы должны иметь возможность использовать этот растровый рисунок как текстуру OpenGL.
Ответ 6
Я посмотрел на пример текста спрайта, и он выглядит ужасно сложным для такой задачи, я тоже рассматривал визуализацию текстуры, но меня беспокоит поражение производительности, которое может вызвать.
Мне просто нужно пойти с видом вместо этого и беспокоиться о портировании, когда пришло время пересечь этот мост:)
Ответ 7
Посмотрите на образец "Sprite Text" в образцы GLSurfaceView.
Ответ 8
Если вы настаиваете на использовании GL, вы можете отобразить текст на текстурах. Предполагая, что большая часть HUD является относительно статической, вам не нужно слишком часто загружать текстуры в текстурную память.
Ответ 9
Взгляните на CBFG
и порт Android для загрузки/рендеринга
код. Вы должны убрать код в свой проект и использовать его
прямо сейчас.
У меня проблемы с этой реализацией. Он отображает только один символ, когда я пытаюсь изменить размер растрового изображения шрифта (мне нужны специальные буквы), целая ничья не получается: (
Ответ 10
ИМХО есть три причины использовать OpenGL ES в игре:
- Избегайте различий между мобильными платформами с использованием открытого стандарта;
- Чтобы иметь больший контроль над процессом рендеринга,
- Чтобы воспользоваться параллельной обработкой GPU,
Текст чертежа всегда является проблемой в дизайне игры, потому что вы рисуете вещи, поэтому вы не можете иметь внешний вид и обычную активность, с виджетами и т.д.
Вы можете использовать фреймворк для создания шрифтов Bitmap из шрифтов TrueType и их рендеринга. Все рамки, которые я видел, работают одинаково: генерируйте координаты вершин и текстур для текста в времени рисования. Это не самое эффективное использование OpenGL.
Лучший способ - выделить удаленные буферы (объекты буфера вершин - VBOs) для вершин и текстур в начале кода, избегая ленивых операций переноса памяти во время рисования.
Имейте в виду, что игрокам не нравится читать текст, поэтому вы не будете писать длинный динамически сгенерированный текст. Для меток вы можете использовать статические текстуры, оставляя динамический текст для времени и оценки, и оба они имеют числовое число с несколькими символами.
Итак, мое решение прост:
- Создать текстуру для общих меток и предупреждений;
- Создать текстуру для чисел 0-9, ":", "+" и "-". Одна текстура для каждого символа;
- Создайте удаленные VBO для всех позиций на экране. Я могу отображать статический или динамический текст в этих позициях, но VBOs являются статическими;
- Создайте только одну текстуру VBO, так как текст всегда отображается в одном направлении;
- Во время рисования я создаю статический текст;
- Для динамического текста я могу заглянуть в позицию VBO, получить текстуру персонажа и нарисовать ее, персонаж за раз.
Операции рисования выполняются быстро, если вы используете удаленные статические буферы.
Я создаю XML файл с положениями экрана (на основе процентного соотношения по диагонали экрана) и текстур (статические и символы), а затем загружаю этот XML перед рендерингом.
Чтобы получить высокий коэффициент FPS, вы должны избегать генерации VBOs во время рисования.
Ответ 11
Я искал это в течение нескольких часов, это была первая статья, которую я получил, и, хотя у нее есть лучший ответ, самые популярные ответы, которые, я думаю, не имеют значения. Конечно, за то, что мне нужно.
Вейшел и shakazed ответы были прямо на кнопку, но немного затенены в статьях.
Поставить вас в проект. Вот:
Просто создайте новый Android-проект на основе существующего образца. Выберите ApiDemos:
Посмотрите папку с исходным кодом
ApiDemos/src/com/example/android/apis/graphics/spritetext
И вы найдете все, что вам нужно.
Ответ 12
Для статического текста:
- Сгенерировать изображение со всеми словами, используемыми на вашем ПК (например, с помощью GIMP).
- Загрузите это как текстуру и используйте ее как материал для плоскости.
Для длинного текста, который нужно обновлять время от времени:
- Пусть андроид рисует растровое изображение (решение JVitela).
- Загрузите это как материал для плоскости.
- Используйте разные координаты текстуры для каждого слова.
Для числа (отформатировано 00.0):
- Создайте изображение со всеми числами и точкой.
- Загрузите это как материал для плоскости.
- Используйте ниже шейдер.
-
В вашем событии onDraw обновляется только переменная значения, отправленная в шейдер.
precision highp float;
precision highp sampler2D;
uniform float uTime;
uniform float uValue;
uniform vec3 iResolution;
varying vec4 v_Color;
varying vec2 vTextureCoord;
uniform sampler2D s_texture;
void main() {
vec4 fragColor = vec4(1.0, 0.5, 0.2, 0.5);
vec2 uv = vTextureCoord;
float devisor = 10.75;
float digit;
float i;
float uCol;
float uRow;
if (uv.y < 0.45) {
if (uv.x > 0.75) {
digit = floor(uValue*10.0);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.5) / devisor, uRow / devisor) );
} else if (uv.x > 0.5) {
uCol = 4.0;
uRow = 1.0;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.0) / devisor, uRow / devisor) );
} else if (uv.x > 0.25) {
digit = floor(uValue);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.5) / devisor, uRow / devisor) );
} else if (uValue >= 10.0) {
digit = floor(uValue/10.0);
digit = digit - floor(digit/10.0)*10.0;
i = 48.0 - 32.0 + digit;
uRow = floor(i / 10.0);
uCol = i - 10.0 * uRow;
fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.0) / devisor, uRow / devisor) );
} else {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
} else {
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
gl_FragColor = fragColor;
}
Над кодом работает атлас текстуры, где числа начинаются с 0 в 7-м столбце второй строки атласа шрифта (текстуры).
Обратите внимание на https://www.shadertoy.com/view/Xl23Dw для демонстрации (с неправильной текстурой)