Що є найсучаснішим для візуалізації тексту у OpenGL станом на версію 4.1? [зачинено]


199

У OpenGL вже існує низка питань щодо відображення тексту, такі як:

Але в основному те, що обговорюється, - це надання текстурованих квадратиків за допомогою конвеєра з фіксованою функцією. Безумовно, шейдери повинні зробити кращий шлях.

Я не дуже переймаюся інтернаціоналізацією, більшість моїх рядків будуть графічними позначками (дата та час або чисто числові). Але сюжети будуть відтворені зі швидкістю оновлення екрану, і текст може бути зовсім небагато (не більше декількох тисяч гліфів на екрані, але достатньо, щоб апаратне прискорене розташування було б непоганим).

Який рекомендований підхід для передачі тексту за допомогою сучасного OpenGL? (Посилання на існуюче програмне забезпечення з використанням підходу є хорошим свідченням того, що воно працює добре)

  • Шейдери з геометрії, які приймають, наприклад, положення та орієнтацію, послідовність символів і випромінюють текстуровані квадратики
  • Шейдери з геометрії, які надають векторні шрифти
  • Як було сказано вище, але замість цього використовуються шейдери тесселяції
  • Обчислювальний шейдер, щоб зробити растерізацію шрифту

10
Я не в змозі відповісти на сучасний стан, орієнтуючись в першу чергу на OpenGL ES, але тесселяція TTF за допомогою тесселятора GLU та подання його як геометрія за допомогою старого конвеєра з фіксованою функціональністю з керуванням, обчисленим на процесорі, давали хороші візуальні результати на анти -забезпечення обладнання та хороші показники роботи майже майже десять років тому. Тож не тільки за допомогою шейдерів ви можете знайти «кращий» спосіб (звичайно, залежно від критеріїв). FreeType може виплювати межі гліфів Bezier та інформацію про кернування, тому ви можете працювати в режимі реального часу з TTF під час виконання.
Томмі

QML2 (з Qt5) робить кілька цікавих хитрощів з OpenGL та полями відстані під час візуалізації тексту: blog.qt.digia.com/blog/2012/08/08/native-looking-text-in-qml-2
mlvljr

Тому я не втрачаю його знову, ось бібліотека, яка реалізує метод дистанційного поля Valve. code.google.com/p/glyphy Я не пробував цього. Також, можливо, варто подивитися: code.google.com/p/signed-distance-field-font-generator
Timmmm

7
ця "поза темою" - це прокляття переповнення стека. серйозно?
Ніколаос Джотіс

1
більш наївний «як це зробити» версію: stackoverflow.com/questions/8847899 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Відповіді:


202

Обриси рендерингу, якщо ви не надаєте всього лише десяток символів, залишається "не йти" через кількість вершин, необхідних на один символ, щоб наблизити кривизну. Хоча існують підходи до оцінювання кривих безьє в піксельному шейдері, вони страждають від того, що вони не легко піддаються антиадалізірованию, що тривіально за допомогою квадратичного текстурованого квадрату на відстані, а оцінка кривих в шейдері все ще обчислювально набагато дорожче, ніж потрібно.

Найкращі компроміси між "швидким" та "якісним" - це все-таки текстуровані квадратики з підписаною текстурою поля відстані. Це дуже трохи повільніше, ніж використання звичайного звичайного текстурованого квадратика, але не дуже. Якість, з іншого боку, полягає в зовсім іншому бальному парку. Результати по-справжньому приголомшливі, це так швидко, як ви можете отримати, і такі ефекти, як світіння, також нелегко додати. Крім того, при необхідності техніку можна зручно перенести на старі апаратури.

Дивіться знаменитий папір Valve про техніку.

Методика концептуально схожа на те, як працюють неявні поверхні (метаболи тощо), хоча вона не генерує багатокутників. Він працює повністю в піксельному шейдері і приймає відстань, відібрану від текстури, як функцію відстані. Все вище обраного порогу (як правило, 0,5) - "in", все інше - "out". У найпростішому випадку на 10-річному апараті, що не працює на шейдері, встановлення порогу альфа-тесту до 0,5 зробить саме таку річ (хоча без спеціальних ефектів і антиаліазингу).
Якщо ви хочете додати шрифту трохи більше ваги (штучний жирний шрифт), трохи менший поріг зробить трюк, не змінюючи жодного рядка коду (просто змініть форму "font_weight"). Для ефекту світіння просто розглядається все, що перевищує один поріг, як "в", а все над іншим (меншим) порогом як "поза, але в світіння", і середнє значення LERP. Антилізінг працює аналогічно.

Використовуючи 8-бітове значення підписаного відстані, а не один біт, ця методика збільшує ефективну роздільну здатність вашої карти текстури в 16 разів у кожному вимірі (замість чорного та білого використовуються всі можливі відтінки, таким чином, у нас в 256 разів більше інформація з використанням одного і того ж сховища). Але навіть якщо ви збільшуєте далеко за 16 разів, результат все одно виглядає цілком прийнятним. Довгі прямі лінії з часом стануть трохи хитрішими, але типових артефактів для вибірки не буде.

Ви можете використовувати шейдер для геометрії для генерації квадратиків з точок (зменшення пропускної здатності шини), але, чесно кажучи, виграші досить незначні. Те саме стосується інстальованого відображення символів, як описано в GPG8. Накладні витрати припадають на амортизацію лише в тому випадку, якщо у вас є багато тексту для малювання. На мою думку, виграш не пов’язаний із додатковою складністю та неспроможністю відновлення. Крім того, ви або обмежені кількістю постійних регістрів, або вам доводиться читати з буфера текстури, що є неоптимальним для узгодженості кешу (і наміром було оптимізувати для початку!).
Простий, простий старий вершинний буфер настільки ж швидкий (можливо, швидший), якщо ви заплануєте завантаження трохи вперед за часом і буде працювати на кожному обладнання, побудованому протягом останніх 15 років. І це не обмежується якоюсь конкретною кількістю символів у вашому шрифті, а також певною кількістю символів для відображення.

Якщо ви впевнені, що у вашому шрифті не більше 256 символів, текстурні масиви, можливо, варто розглянути, щоб зняти пропускну здатність шини аналогічним чином, як генерувати квадратики з точок на шейдері геометрії. При використанні текстури масиву координати текстури всіх квадратиків мають однакові, постійні sта tкоординати і відрізняються лише rкоординатою, яка дорівнює індексу символів для візуалізації.
Але, як і в інших методах, очікувані вигоди незначні за рахунок того, що вони несумісні з обладнанням попереднього покоління.

Існує зручний інструмент Джонатана Даммера для створення текстур відстані: сторінка з описом

Оновлення:
Як нещодавно вказувалося в програмованій вершині витягування (Д. Ракос, "OpenGL Insights", стор. 239), немає значної додаткової затримки або накладних витрат, пов'язаних із витягненням вершинних даних програмно з шейдера на новітні покоління GPU, порівняно з тим, як робити те саме, використовуючи стандартну фіксовану функцію.
Крім того, останні покоління графічних процесорів мають все більш і більш розумні розміри кешів L2 загального призначення (наприклад, 1536kiB на nvidia Kepler), тому можна очікувати непослідовної проблеми доступу, коли витягувати випадкові зрушення для чотирьох кутів з текстури буфера менше проблема.

Це робить ідею витягування постійних даних (наприклад, квадратиків) з текстури буфера більш привабливою. Таким чином, гіпотетична реалізація могла б звести до мінімуму передачу PCIe та пам'яті, а також пам'яті GPU, з таким підходом:

  • Завантажуйте лише індекс символів (один на символ, який потрібно відобразити) як єдиний вхід до вершинного шейдера, який передає цей індекс gl_VertexID, і посилюйте його до 4-х точок в шейдері геометрії, все ще маючи індекс символів та ідентифікатор вершини (це буде "gl_primitiveID, доступним у вершинній шейдері") як єдиний атрибут, і фіксує це за допомогою зворотного зв'язку з перетворенням.
  • Це буде швидко, тому що є лише два вихідних атрибути (головне вузьке місце в GS), і він близький до "no-op" в іншому випадку на обох етапах.
  • Зв’яжіть текстуру буфера, яка містить для кожного символу шрифту текстуровані вершини квадрата відносно базової точки (це в основному "метрики шрифту"). Ці дані можна стиснути до 4 чисел на квадратик, зберігаючи лише зміщення нижньої лівої вершини та кодуючи ширину та висоту вікна, вирівнюваного по осі (припустимо, що напівплавків буде це 8 байт постійного буфера на символ - типовий шрифт 256 символів міг повністю вміститися в кеш-пам'ять L1 2kiB).
  • Встановити форму для базової лінії
  • Зв’яжіть текстуру буфера з горизонтальними зміщеннями. Їх, можливо, можна було б навіть обчислити на графічному процесорі, але це набагато простіше та ефективніше з подібними речами в процесорі, оскільки це суворо послідовна операція і зовсім не банальна (подумайте про кернінг). Крім того, знадобиться ще одна передача зворотного зв'язку, яка була б ще одним моментом синхронізації.
  • Відображаючи раніше створені дані з буфера зворотного зв’язку, вершина шейдера витягує горизонтальне зміщення базової точки та зміщення кутових вершин від буферних об'єктів (використовуючи примітивний ідентифікатор та індекс символів). Оригінальний ідентифікатор вершин поданих вершин тепер є нашим «примітивним ідентифікатором» (пам’ятайте, що GS перетворило вершини на квадри).

Так, в ідеалі можна зменшити необхідну смугу вершин на 75% (амортизовано), хоча вона зможе надати лише один рядок. Якщо хотіли б мати змогу візуалізувати кілька рядків за один виклик малювання, потрібно було б додати базову лінію до текстури буфера, а не використовувати рівномірний (зменшення пропускної здатності збільшується).

Однак, навіть якщо припустити 75-відсоткове зменшення - оскільки дані вершин для відображення "розумних" обсягів тексту лише десь близько 50-100кіБ (що практично дорівнює нулюдо GPU або PCIe-шині) - я все ще сумніваюся, що додаткова складність та втрата зворотної сумісності дійсно вартують клопоту. Зниження нуля на 75% все ще лише нульове. Я, правда, не спробував вищезазначеного підходу, і для того, щоб зробити справді кваліфіковану заяву, знадобиться більше досліджень. Але все-таки, якщо хтось не зможе продемонструвати справді приголомшливу різницю у виконанні (використовуючи "нормальну" кількість тексту, а не мільярди символів!), Моя точка зору залишається, що для даних вершин простий, звичайний старий вершинний буфер є виправдано досить хорошим вважати частиною "найсучаснішого рішення". Це просто і прямо, це працює, і це добре працює.

Вже посилаючись на " OpenGL Insights " вище, варто також вказати на розділ "2D-рендеринг форми за допомогою дистанційних полів" Стефана Густавсона, який дуже детально пояснює подання поля на відстані.

Оновлення 2016:

Тим часом існує кілька додаткових прийомів, які мають на меті вилучити артефакти кутового округлення, які стають тривожними при надзвичайних збільшеннях.

Один із підходів просто використовує поля псевдо відстані замість полів відстані (різниця полягає в тому, що відстань - найкоротша відстань не до фактичного контуру, а до контуру чи уявної лінії, що виступає через край). Це дещо краще, і працює з однаковою швидкістю (однаковий шейдер), використовуючи однаковий об'єм текстурної пам'яті.

Інший підхід використовує медіану з трьох у триканальних деталях текстури та реалізації, доступних у github . Це спрямоване на покращення порівняно із та / або хаками, які використовувались раніше для вирішення проблеми. Хороша якість, трохи, майже не помітно, повільніше, але використовує втричі більше пам'яті текстури. Крім того, зайві ефекти (наприклад, світіння) важче виправити.

Нарешті, зберігання фактичних кривих безьє, що складають символи, та оцінювання їх у фрагменті шейдера стало практичним , з дещо неповноцінною продуктивністю (але не настільки, що це проблема) та приголомшливими результатами навіть при найвищих масштабах.
Демонстрація веб-версії WebGL з великою формою PDF з цією технікою в режимі реального часу доступна тут .


1
Вони виглядають досить непогано (навіть при наївній фільтрації та за відсутності міпапингу, оскільки у вас дуже маленькі текстури і дані добре інтерполюються). Особисто я вважаю, що вони навіть виглядають краще, ніж "справжня" річ у багатьох випадках, тому що немає ніяких дивацтв як натяку, які часто створюють речі, які я сприймаю як "дивні". Наприклад, менший текст несподівано не стає жирним без очевидних причин, а також межі поп-пікселів - ефекти, які ви часто бачите за допомогою "реальних" шрифтів. Можливо, для цього є історичні причини (дисплеї в 1985 р. / Ч.), Але сьогодні, поза моїм розумінням, це має бути таким.
Деймон

2
Працює та виглядає чудово, дякую за спільний доступ! Для тих, хто хоче HLSL, фрагмент шейдерного джерела дивіться тут . Ви можете адаптувати це для GLSL, замінивши clip(...)рядок на if (text.a < 0.5) {discard;}(або text.a < threshold). HTH.
Інженер

1
Дякуємо за оновлення. Мені б хотілося, щоб я міг знову взяти участь
Бен Войгт

2
@NicolBolas: Ви, здається, не дуже уважно читали. Обидва питання пояснюються у відповіді. Кеплер наводиться як приклад "останнього роду", немає другого проходу (і це пояснено чому), і я заявляю, що не вірю, що гіпотетична техніка збереження пропускної здатності помітно швидша або взагалі коштує неприємностей. Однак віра нічого не означає - варто було б спробувати це знати (я ніколи не вважаю, що в будь-якому випадку малювати «нормальні» кількості тексту вузьким місцем). Тим не менш, це може бути варте того, коли людина відчайдушно ставиться до пропускної здатності і має "ненормальну" кількість тексту.
Деймон

3
@NicolBolas: Ти маєш рацію щодо цього речення, вибач. Це дійсно трохи вводить в оману. У попередньому абзаці я писав: "Можливо, навіть можна створити це на GPU, але це вимагатиме зворотного зв'язку та ... isnogud". - але потім помилково продовжували "генеровані дані з буфера зворотного зв'язку" . Я це виправлю. Насправді я перепишу повну річ у вихідні, тож це менш неоднозначно.
Деймон

15

http://code.google.com/p/glyphy/

Основна відмінність між GLGL-програмою та іншими OpenGL-рендерами на базі SDF полягає в тому, що більшість інших проектів відбирають SDF у текстуру. У цьому є всі звичайні проблеми, які мають вибірки. Тобто він спотворює обриси і низької якості. Натомість GLyphy представляє SDF, використовуючи фактичні вектори, подані до GPU. Це призводить до дуже якісної візуалізації.

Мінусом є те, що код призначений для iOS з OpenGL ES. Я, мабуть, збираюся зробити порт OpenX 4.x для Windows / Linux (хоча, сподіваюся, автор додасть реальну документацію).


3
Усі, хто цікавиться GLyphy, мабуть, слідкують за розмовою автора на Linux.conf.au 2014: youtube.com/watch?v=KdNxR5V7prk
Fizz

14

Найпоширенішою технікою все ж є фактурні квадроцикли. Однак у 2005 році LORIA розробила щось, що називається векторними текстурами, тобто надання векторної графіки як текстури на примітивах. Якщо ви використовуєте це для перетворення шрифтів TrueType або OpenType у векторну текстуру, ви отримуєте це:

http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005


2
Чи знаєте ви про будь-які реалізації, що використовують цю техніку?
luke

2
Ні (як у виробничих класах), але в роботі Кілгард (див. Мою відповідь нижче за посиланням) є коротка критика, яку я підсумовую як: ще не практична. У цій галузі проведено більше досліджень; новіша робота, яку цитує Kilgard, включає research.microsoft.com/en-us/um/people/hoppe/ravg.pdf та uwspace.uwaterloo.ca/handle/10012/4262
Fizz

9

Я здивований, що дитину Марка Кілгара , NV_path_rendering (NVpr), ніхто з вищезгаданого не згадував. Хоча цілі є загальнішими за візуалізацію шрифту, він також може виводити текст із шрифтів та з керуванням. Він навіть не вимагає OpenGL 4.1, але наразі це розширення для постачальника / Nvidia. В основному це перетворює шрифти в шляхи, використовуючи glPathGlyphsNVякі залежать від бібліотеки freetype2, щоб отримати метрики тощо. Потім ви також можете отримати доступ до інформації про кернінг glGetPathSpacingNVта використовувати загальний механізм візуалізації каналу NVpr для відображення тексту з використанням "перетворених" шрифтів. (Я ставлю це в лапках, оскільки реального перетворення немає, криві використовуються як є.)

На жаль, записана демонстрація можливостей шрифту NVpr, на жаль, не особливо вражає. (Може бути , хто - то повинен зробити один уздовж ліній багато привабливим SDF демо можна знайти на межтрубочние ...)

Розмова про презентацію API NVpr для частини шрифтів починається тут і продовжується в наступній частині ; трохи прикро, як поділяється ця презентація.

Більш загальні матеріали про NVpr:

  • Центр Nvidia NVpr , але деякі матеріали на цільовій сторінці не є найсучаснішими
  • Папір Siggraph 2012 для мізків методу візуалізації шляху, який називається "трафарет, тоді обкладинка" (StC); стаття також коротко пояснює, як працює конкуруючий технік, як Direct2D. Шрифти, пов'язані з шрифтом, передані у додаток до статті . Також є деякі додатки, такі як відео / демонстрації .
  • Презентація GTC 2014 для статусу оновлення; у двох словах: тепер його підтримує компанія Google Skia (Nvidia представила код наприкінці 2013 та 2014 років), яка, в свою чергу, використовується в Google Chrome і [незалежно від Skia, я думаю] у бета-версії Adobe Illustrator CC 2014
  • офіційна документація в реєстрі розширень OpenGL
  • USPTO надав щонайменше чотири патенти на Kilgard / Nvidia у зв'язку з NVpr, про що ви, мабуть, повинні знати, якщо ви хочете реалізувати StC самостійно: US8698837 , US8698808 , US8704830 та US8730253 . Зауважте, що з цим пов'язано ще 17 документів USPTO як "також опубліковані як", більшість з яких є заявками на патент, тому цілком можливо, більше таких патентів може бути видано.

А оскільки слово "трафарет" не спричинило жодної звернення на цій сторінці до моєї відповіді, схоже, підмножина спільноти SO, яка брала участь у цій сторінці, настільки, наскільки це було досить багато, не знала про тесселяцію, трафарет-буфер- засновані методи для візуалізації контуру / шрифту в цілому. У Kilgard на форумі opengl є схожий на поширені запитання, який може висвітлити, чим методи візуалізації вільних теселяцією відрізняються від звичайної 3D графіки, навіть якщо вони все ще використовують [GP] GPU. (NVpr потрібен CUDA-чіп.)

З історичної точки зору Кілгард також є автором класичного "Простий API на основі OpenGL для текстурованого текстурованого тексту", SGI, 1997 , який не слід плутати з NVpr на основі трафарету, який дебютував у 2011 році.


Більшість, якщо не всі останні методи, обговорювані на цій сторінці, включаючи методи на основі трафарету, такі як NVpr або SDF-методи, такі як GLyphy (про які я більше не обговорюю тут, оскільки інші відповіді вже охоплюють це), однак мають одне обмеження: вони підходить для великого відображення тексту на звичайних (~ 100 DPI) моніторах без змішаних на будь-якому рівні масштабування, а також вони добре виглядають, навіть при невеликих розмірах, на дисплеях, що нагадують сітківку, з високою DPI. Вони не повністю забезпечують те, що дає вам Direct2D + DirectWrite від Microsoft, а саме, натякаючи на невеликі гліфи на основних дисплеях. (Для візуального огляду натяків загалом див . Наприклад цю сторінку друкарні . Більш поглиблений ресурс розміщено на antigrain.com .)

Мені невідомі будь-які відкриті та продумані матеріали на основі OpenGL, які б могли зробити те, що може зробити Microsoft, натякаючи на даний момент. (Я визнаю невігластво внутрішніх процесорів Apple OS X GL / Quartz, оскільки, наскільки мені відомо, Apple не опублікувала, як вони роблять рендеринг шрифту / контуру на основі GL. Схоже, що OS X, на відміну від MacOS 9, не робить взагалі натякають, що дратує деяких людей .) У будь-якому випадку, є одна дослідницька робота в 2013 році, яка стосується натяків на шаблони OpenGL, написані Ніколасом П. Ругє; напевно, варто прочитати, якщо вам потрібно зробити підказку з OpenGL. Хоча може здатися, що бібліотека типу freetype вже виконує всю роботу, коли йдеться про натяк, це насправді не так з наступної причини, яку я цитую з паперу:

Бібліотека FreeType може розповсюджувати гліф, використовуючи підпіксель для згладжування в режимі RGB. Однак це лише половина проблеми, оскільки ми також хочемо домогтися позиціонування субпікселів для точного розміщення гліфів. Відображення текстурованого квадратика в координатах дробових пікселів не вирішує проблему, оскільки це призводить лише до інтерполяції текстури на рівні цілого пікселя. Натомість ми хочемо досягти точного зсуву (між 0 та 1) в допіці пікселів. Це можна зробити за допомогою фрагмента шейдера [...].

Рішення не зовсім тривіальне, тому я не збираюся тут намагатися пояснювати це. (Папір відкритого доступу.)


Ще одна річ, яку я дізнався з роботи Рузьє (і яку, схоже, Kilgard не вважав), полягає в тому, що повноваження шрифту (Microsoft + Adobe) створили не один, а два методи специфікації кернінгу. Стара основана на так званій керні таблиці, і вона підтримується вільним типом . Новий називається GPOS, і його підтримують лише новіші бібліотеки шрифтів, такі як HarfBuzz або pango у світі вільного програмного забезпечення. Оскільки NVpr, схоже, не підтримує жодної з цих бібліотек, kerning може не працювати з NVpr для деяких нових шрифтів; Є деякі з тих, хто, очевидно, в дикій природі, згідно з цим обговоренням на форумі .

Нарешті, якщо вам потрібно зробити складний макет тексту (CTL), вам здається, що в даний час вам не пощастило з OpenGL, оскільки для цього не існує бібліотеки, заснованої на OpenGL. (DirectWrite з іншого боку може обробляти CTL.) Є бібліотеки з відкритим джерелом на зразок HarfBuzz, які можуть надати CTL, але я не знаю, як би ви змусили їх працювати добре (як при використанні методів на основі трафарету) через OpenGL. Вам, мабуть, доведеться написати код клею, щоб витягти переформовані контури та подати їх у рішення на основі NVpr або SDF як шляхи.


4
Я не згадував NV_path_rendering, тому що це розширення, яке є власником постачальника, щоб зробити речі гіршими. Я зазвичай намагаюся давати відповіді лише на методи, які є загальноприйнятими.
datenwolf

1
Ну, я можу з певною мірою погодитися з цим. Сам метод ("трафарет, тоді обкладинка") насправді не важко реалізувати безпосередньо в OpenGL, але він матиме високі накладні витрати команд, якщо це буде зроблено наївно таким чином, як закінчилися попередні спроби на основі трафарету. Skia [через Ганеша] спробував на основі трафарету рішення, але відмовився від нього, повідомляє Kilgrad. Те, як його реалізує Nvidia, шар нижче, використовуючи можливості CUDA, примушує його виконувати. Ви можете спробувати "мантію" StC самостійно, використовуючи цілу купу розширень EXT / ARB. Але майте на увазі, що Kilgard / Nvidia мають дві заявки на патент на NVpr.
Фізз

3

Я думаю, що найкращим варіантом буде переглянути графіку в Каїрі з резервним OpenGL.

Єдиною проблемою, яка була у мене при розробці прототипу з ядром 3.3, було застаріле використання функції в OpenGL бекенді. Це було 1-2 роки тому, тож ситуація могла покращитися ...

У будь-якому випадку, я сподіваюся, що в майбутньому драйвери графічної версії opengl будуть впроваджувати OpenVG.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.