Как я могу управлять текстурой кеша в OpenGL?

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

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

Итак, передо мной текстура 2048x2048, в которую я могу поместить любые строки, которые я могу уместить, поскольку они запрашиваются приложением для целей кэширования. Я быстро понял, что отслеживание свободного пространства, доступного в двухмерном пространстве, не является тривиальной задачей.

Я смотрел на такие вещи, как Best Fit и Next fit, но они кажутся подходящими для 1d пространств.

Как я могу управлять этой текстурой кеша в OpenGL?

Редактировать: с тех пор я узнал, что это пример «проблемы с двумерной упаковкой».


person Martin    schedule 27.03.2009    source источник


Ответы (3)


У вас есть проблема с упаковкой bin.

Сначала плохие новости: это NP-сложно, поэтому стоит найти оптимальное решение.

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

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

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

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

Кроме того: если вы сделаете свои блоки сетки кратными 8 пикселям и сможете уменьшить сглаживание до 4 бит, вы сможете сжимать глифы в один из сжатых форматов DXT или S3TC на лету. Таким образом, потерянное текстурное пространство становится не проблемой.

person Nils Pipenbrinck    schedule 27.03.2009

Если у вас мало текстурной памяти, вы можете взглянуть на технику рендеринга шрифта «Distance Field» или «Signed Distance Field». Вы можете использовать текстуру 512x512 для каждого семейства шрифтов, и вы можете отображать идеально сглаженный текст любого размера.

Для этого алгоритма вам нужно сгенерировать специальную текстуру, которая содержит расстояние от текселя до края текстуры. Взгляните на оригинальную статью ребят из Valve: http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf . Есть несколько фреймворков, которые используют это. Например, последняя версия Qt использует поле расстояния со знаком для рендеринга текста.

person Community    schedule 15.07.2012
comment
Эх, надо было проверить дату перед публикацией :) - person ; 15.07.2012
comment
Для полной реализации вы можете посмотреть libcinder. - person Marco van de Voort; 11.07.2015

Я решил использовать простой подход. Разделите текстуру на ряды переменной высоты. Первая текстура, размещаемая в ряду, определяет высоту ряда. Если текстура может поместиться в существующий ряд по высоте, проверьте, достаточно ли осталось ширины, и поместите ее туда. В противном случае начните новую строку. Если новую строку нельзя запустить, не кэшируйте строку.

person Martin    schedule 31.03.2009