Pixi.js: Предложение: Улучшение отрисовки текста

Созданный на 5 апр. 2020  ·  27Комментарии  ·  Источник: pixijs/pixi.js

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

  • Поля расстояния со знаком: этот метод преобразует текст в текстуру (с помощью Canvas 2D API) и применяет преобразование расстояния. Проще говоря, преобразование расстояния установит значение каждого пикселя в выходной текстуре равным расстоянию от этого пикселя до ближайшего контура текста во входной текстуре. pixi-sdf-text является примером: https://github.com/PixelsCommander/pixi-sdf-text

  • VTM: векторные карты текстур кодируют неоднородности кривых на уровне пикселей в текстурах.

  • Точная визуализация кривой Безье: при этом шрифт отображается «как есть» за счет мозаики всего, кроме кривых. Кривые отрисовываются с помощью специального фрагментного шейдера (выборка кривой не производится, она отрисовывается точно на GPU со сглаживанием): https://www.microsoft.com/en-us/research/wp-content/uploads /2005/01/p1000-loop.pdf. Я создал демонстрацию квадратичной кривой Безье: https://codepen.io/sukantpal/pen/GRJawBg?editors=0010

Мы с @bigtimebuddy обсудили эти методы и подумали, что третий подход является лучшим, потому что:

  • Для SDF требуются предварительно сгенерированные атласы. Создание многоканальных SDF очень сложно (если мы хотим делать это во время выполнения).

  • VTM слишком сложны для использования только шрифтов.

  • Точные кривые Безье просто требуют, чтобы вы визуализировали шрифт как путь, как и все остальное в графике.

Самый полезный комментарий

@eXponenta, пожалуйста, перестань быть таким враждебным. Мы изучаем подходы, пока ничего твердого нет. Пожалуйста, будьте конструктивны и не используйте оскорбления.

Все 27 Комментарий

Его не должно быть в ядре.
Это тяжелый пакет, и он ДОЛЖЕН БЫТЬ реализован вне основного пакета, основная команда не должна беспокоиться о его реализации.

Pixi SDF - правильный пример.

Пожалуйста, не пытайтесь сделать Phaser из PIXI

Я хотел бы дать еще немного контекста. Я попросил @SukantPal изучить альтернативные подходы Text / BitmapText, которые имеют разные компромиссы. В частности, если мы сможем найти что-то, что работает лучше, чем текст, и отлично выглядит.

Думаю, здесь есть несколько подходов. Некоторые из них могут быть подходящими как плагины третьей части, некоторые могут быть в репо, но не в комплекте, а некоторые могут заменить / дополнить текущий API. Давайте выясним, какой из подходов к рендерингу текста является наиболее плодотворным, когда он оптимизирует производительность, но с меньшим компромиссом для BitmapText.

Есть несколько критериев, по которым я буду судить о хорошем отображаемом объекте Text:

  • Хорошая производительность во время выполнения - рендеринг и изменение текста не требуют больших затрат.
  • Мало памяти - низкое использование ОЗУ
  • Малые зависимости - размер файла отпечатка зависимостей невелик
  • Отличная точность - хорошо работает с разными разрешениями
  • Гибкий стиль - поддержка штрихов, падающих теней, градиентов
  • Поддерживает языки с большими символами - например, китайский, японский, корейский.
  • Обратная совместимость - работает с Context2D

| | Perf | Память | Зависимости | Верность | Укладка | CJK | Context2d |
| - | - | - | - | - | - | - | - |
| Текст | 👎 | 👎 | 👍 | 👍 | 👍 | 👍 | 👍 | 👍 |
| BitmapText | 👍 | 👎 | 👍 | 👎 | 👎 | 👎 | 👍 |

В порядке.
Описывает fragment interpolation и все неродные реализации:

  1. Требуется дополнительный шейдер и дополнительные данные - это предотвратит пакетирование.
  2. При изменении требуется перестроить геометрию (стр.3).
  3. Требовать таблицу глифов для всех глифов, существующих в языке, которые требуют полной загрузки определенного TTF в память, потому что ot не может поддерживать потоковую передачу, а затем анализировать ее. Похоже, как SWF.
    Потому что мы не можем загрузить системный шрифт как фигуру - мы не можем его использовать.
  4. Специфичные для языка правила перемещаются в команду lib из команды разработчиков, которые реализуют правила рендеринга: ltr / rtl, правила конкатенации глифов хинди / арабского языка и т. Д. Так же, как перемещение 10% браузера в lib. Unity еще не реализовал это правильно.
  5. Тяжелый шейдер с дополнительными аргументами в пользу поддержки стилей. Это увеличивает стоимость рендеринга, потому что мы должны рендерить его в реальном времени.
    И, конечно же, мы должны кэшировать это как текстуру.

@eXponenta

  • Текст можно группировать, но не с другими элементами, например с графикой.

  • Текущая реализация Text кэширует каждый глиф несколько раз (если буква используется несколько раз в нескольких PIXI.Texts). Лучше иметь одну геометрию на глиф. Кроме того, вам не нужно кешировать шрифты разных размеров.

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

  • Мы можем использовать библиотеку для разбора шрифтов. Преобразование в геометрию тривиально.

  • Я не знаю, что такое правила конкатенации глифов. Могли бы вы объяснить?

  • Слева направо против справа налево - если вы хотите перевернуть буквы, вы можете. Если вы хотите зеркальное отображение, установите scale.x=-1 внутри.

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

  • Файлы шрифтов, полученные из API, должны быть кэшированы на компьютере пользователя.

Вы очень наивны:

  1. Это должен быть внешний дозатор, потому что для глифов требуются дополнительные атрибуты, такие как привязки Безье, значения тени, привязки градиента ... или все они должны передаваться как униформы - пока, пакетная обработка.
  2. справа налево и слева направо, и их сочетание - очень сложная задача.
    Открытые проблемы в библиотеке рендеринга PDF:
    https://github.com/asciidoctor/asciidoctor-pdf/issues/175
  3. Проблема хинди (и аналогичный язык)
    https://docs.microsoft.com/en-us/typography/opentype/spec/gsub

Мы не можем использовать внешние зависимости, потому что будет та же проблема, что и isMobile или resource-loader .
Сердечник должен быть чистым. Минимальные внешние зависимости.

@eXponenta

  • Смешанный макет (сочетание ltr и rtl) менее важен, чем высокая производительность. Вы всегда можете вернуться к текущему алгоритму. Аналогично Деванагари. Специальные функции, такие как ограничители градиента, также потребуют запасного варианта.

  • Пакетирование здесь может работать, потому что без текстур будет проще. Можно создать плагин типа CanvasGraphicsRenderer .

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

@eXponenta, пожалуйста, перестань быть таким враждебным. Мы изучаем подходы, пока ничего твердого нет. Пожалуйста, будьте конструктивны и не используйте оскорбления.

@eXponenta Вы уверены, что сейчас мы поддерживаем текст с

Другой подход, о котором мы думаем, - это визуализировать каждый глиф с использованием холста 2D (как сейчас) отдельно и кэшировать их в атлас. Атлас можно повторно использовать глобально для всех экземпляров PIXI.Text . Каждая комбинация глиф + размер шрифта + стиль шрифта будет кэшироваться отдельно.

Что вы думаете о том, чтобы принять это в ядро?

Привет, друзья, это действительно здорово - услышать эти новые подходы на столе. @eXponenta , повторяя @bigtimebuddy , давайте оставим его конструктивным, пожалуйста. У вас явно есть хорошее представление о новом предлагаемом подходе, но давайте посмотрим, сможем ли мы смягчить поднятые проблемы и сохранить его дружественным :)

В тексте, вот мои 2 цента (пенсы?).

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

Динамические растровые шрифты

профи

  • Инструментов для создания растровых шрифтов очень мало! Хотел бы снять этот барьер.
  • мы могли создавать текстуры различных размеров с размером текста.
  • Работает с Canvas
  • Производительность, поскольку каждый глиф может быть объединен
  • много крутых эффектов!
  • API потребуется лишь небольшая корректировка:
const textStyle = new TextStyle({
    font:'comic sans',
    fill:'bright green'
});


const bitmapFont = new BitmapFont(textStyle);

минусы

  • все остальные минусы растровых текущих растровых шрифтов: P
  • будет ли динамическое обновление атласа текстур замедляться?

    • Хотя через некоторое время это стабилизируется, и, возможно, его можно будет кэшировать между сеансами?

    • Current Text также должен загружать текстуру каждый раз, когда он меняет кадр, этот подход сделает это меньше?

идеи

  • Может ли кэшироваться текстура, созданная в локальном хранилище? для последующих посещений?
  • Добавляйте только используемые символы, чтобы текстуры были настолько большими, насколько это необходимо. Обновляйте по ходу
  • вставьте фильтры в эту текстуру для получения дополнительных крутых эффектов (контур, тень и т. д.)
  • мы можем уменьшить объем памяти растрового шрифта, не превращая каждый глиф в спрайт?

SDF
Может ли SDF быть продолжением вышеупомянутого подхода? Насколько сложно было бы динамически генерировать эту текстуру? Было бы это супер-дрянным? Мы говорим о большом увеличении кодовой базы?

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

const textStyle = new TextStyle({
    font:'comic sans',
    fill:'bright green',
    sdf:true, <----- how sweet would this be, maybe rename to more user friendly like 'cleanEdges'
});

const sdfFont = new BitmapFont(textStyle);

Точная визуализация кривой Безье

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

Сказав это, может быть, стоит создать прототип, который мы сможем протестировать и немного потрепаться, чтобы подтвердить наше мышление?

Волнующее время для текста: D

Может ли SDF быть продолжением вышеупомянутого подхода? Насколько сложно было бы динамически генерировать эту текстуру? Было бы это супер-дрянным? Мы говорим о большом увеличении кодовой базы?

Генерация SDF дорогостоящая, и есть время упаковки (когда мы упаковываем разные шрифты в атлас), но ее можно кэшировать на клиенте (как и все другие варианты).
Вот его реализация на холсте (хе-хе):
https://github.com/mapbox/tiny-sdf
Но компиляция SDF не совсем правильная (изменение глифа при увеличении / уменьшении размера шрифта)
Выглядит так же удобно, но для MSDF мы должны выполнить его 3 раза (на каждый канал).

ой, это крошечный кусочек кода! Похоже, готов к работе с шейдером!

@GoodBoyDigital Пакет tiny-sdf генерирует одноканальное поле расстояний. При кэшировании текста с меньшим размером шрифта острые углы не получаются. Это можно смягчить путем кэширования при отображении шрифта того же размера.

Одноканальная генерация SDF не должна быть такой уж плохой. Многоканальный SDF лучше, за исключением того, что он слишком сложен. Я не мог понять, как Чумсклый кодирует углы.

Теперь все, что мы рассматриваем, не будет поддерживать смешанный макет RTL и Ltr (как @eXponenta ). Но я не думаю, что мы и сейчас это официально поддерживаем.

Точный подход имеет два преимущества - небольшой размер кеша (вы кешируете вершины, а не все пиксели), сглаживание, даже когда параметр «сглаживание» отключен (я думаю, что сглаживание текста всегда ожидается. Текущая реализация делает это с помощью холста). 2D).

Что касается демонстрации, вы смотрели мою демонстрацию квадратичной кривой Безье? https://codepen.io/sukantpal/pen/GRJawBg?editors=0010

——
Еще одна вещь, которую я и @bigtimebuddy обсуждали как наиболее простое решение, - это продолжать использовать холст 2D и кэшировать глифы в текстуру. Глифы могут быть отображены в виде четырехугольника. Атлас кеша можно повторно использовать между текстами. Конечно, это означает, что большой текст кэшируется с одинаковым размером и, следовательно, большим использованием памяти, когда отображается много текста, но видна только его часть (например, текущая страница в PDF).

Хороший,

Да, не беспокойтесь о rtl или ltr, которые всегда будут доступны через текущий метод, и это проблема, которую все пользовательские методы рендеринга текста потребуют решить позже.
Эти решения. в идеале следует сосредоточить внимание на потреблении памяти и производительности во время выполнения.

Демо Безье - это круто, но я не думаю, что этого достаточно для понимания истинных сложностей, которые могут скрываться, если мы создадим полное предложение.

То, что я написал выше о динамических растровых шрифтах, в значительной степени совпадает с тем, что вы упомянули о кэшировании глифов. Я думаю, что это определенно полезный маршрут для спуска!

В итоге:

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

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

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

@GoodBoyDigital Я думаю, что в демоверсии действительно неплохой текст. Но есть видимые различия, если попытаться найти детали:

Screen Shot 2020-04-06 at 1 34 29 PM

Screen Shot 2020-04-06 at 1 34 35 PM

Текст вверху не резкий - края покачиваются. Каждую комбинацию шрифтов + (разница в размере шрифта ~ 12-15 пикселей) может потребоваться отдельно кэшировать.

Я полностью согласен с переходом на SDF, если эти колебания не важны, или если мы можем использовать кеширование с несколькими размерами шрифта.


Мне тоже подходит простейшее решение 💯tbh!

Всем привет.

Я супер непрофессионал во всех вещах Pixi, но я пользователь GDevelop, который использует Pixi в качестве бэкэнда, и я какое-то время копался в этом для реализации GDevelop PixiJS и рендеринга текста. Это действительно важно для игры, над которой я работаю, в которой много текста. (Вы можете увидеть мои исследования / примеры в проблеме, которую я опубликовал в GDevelop: https://github.com/4ian/GDevelop/issues/1449)

Один из вариантов, который я нашел, был сосредоточен на полном игнорировании проблем с масштабированием текста и их полном устранении, всегда оставляя масштаб текста на 100%, но вместо этого масштабируя размер шрифта текста? Это не зависит от шрифта и, похоже, работает для всех размеров.

Вот пример кода, в котором это делается с помощью Pixi: https://codepen.io/Tazy/pen/wJVExB
Нашел в этой ветке: https://www.html5gamedevs.com/topic/29576-scalable-text-for-pixijs/

На самом деле у меня есть награда за эту проблему, так как я надеялся, что кто-то может просто изменить расширение Pixi Text для GDevelop, но (будучи неспециалистом) я не осознавал, что это была гораздо более серьезная проблема с самой Pixi.

Не знаю, есть ли потенциальные проблемы с этим методом, но, похоже, он позволяет избежать всех проблем с производительностью sdf / msdf / etc.

@ Silver-Streak Если вы имеете в виду увеличение размера шрифта на масштаб, примененный к текстовому экранному объекту, то как это может быть лучше с точки зрения производительности? Материал SDF повышает производительность, потому что вы не выполняете повторный рендеринг с большим размером шрифта.

@ Silver-Streak Конечно, ваше предложение улучшит _quality_, но я не вижу, как это улучшит производительность.

@ Silver-Streak Конечно, ваше предложение улучшит _quality_, но я не вижу, как это улучшит производительность.

Если я не неправильно понимаю, разве изменение размера шрифта не потребует меньше ресурсов, чем масштабирование всего объекта или загрузка в другом средстве визуализации? Опять же, я супер непрофессионал, когда дело доходит до того, как на самом деле работает масштабирование Pixi, для меня просто имело смысл оставить шрифт с исходным разрешением, но просто изменить размер текста будет быстрее, чем его масштабирование. Если это неправильно, извиняюсь за отвлечение.

@ Silver-Streak Масштабирование реализовано как преобразование. У вас есть матрица преобразования - и изменение масштаба в этой матрице - тривиальная операция.

На данный момент текст отображается с помощью Canvas 2D API в холст. Затем он копируется на экран. Изменение масштаба просто изменит координаты экрана, которым сопоставлен текст на холсте.

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

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

Спасибо, что поговорили со мной.

@ Silver-Streak Нет проблем. Однако реализация текста, ориентированного на качество, также не должна быть сложной задачей в WebGL. Некоторые приложения реализуют текст, создавая сетку самостоятельно. Вы можете проанализировать файл шрифта, составить список вершин и разбить его на мозаику. Эти вершины можно визуализировать через сетку.

На больших масштабах это может вызвать небольшие «края», потому что в конечном итоге вы визуализируете текст в виде треугольников. Для еще более высокого качества вы можете использовать шейдер «точной кривой Безье», о котором я говорил в этой беседе - он будет отображать кривые как кривые, а не как треугольники.

Если вам нужна помощь с качеством текста, я могу помочь вам, ребята :)

@SukantPal Я определенно не участвую в GDevelop (и вы бы не хотели, чтобы я был. В жизни я преимущественно аналитик бизнес-систем / DevOps, а не разработчик 😄), хотя мне нравится этот проект и я активен в сообществе . Я также знаю, что есть и другие члены сообщества, которые хотели бы увидеть решение для повышения качества масштабируемого текста.

Однако, если вы хотите взглянуть на проблему в сообщении, у меня также есть награда за нее на Bountysource, которая открыта для всех. Я не хочу больше занимать здесь свободное пространство, поскольку очевидно, что вокруг Pixi в целом идет гораздо более глубокий разговор, и мое предложение не было таким точным, как я думал.

@ Silver-Streak Я мог бы взглянуть, так как мне нечего делать в сезон короны

Я знаю, что это закрытая тема, но я уверен, что все все еще ищут лучший способ улучшить рендеринг текста. Я заметил, что у кого-то была реализация msdf, которая работала с Pixi v5. https://github.com/cjsjy123/pixi-msdf-text-v5 Выяснилось, что я хотел бы упомянуть об этом всем заинтересованным.

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

Была ли эта страница полезной?
0 / 5 - 0 рейтинги