Рендеринг текста в WebVR

В деталях

Посмотреть сайт

Within ( https://with.in/ ) — это платформа для рассказывания историй в виртуальной реальности. Поэтому, когда команда услышала о WebVR в 2015 году, мы сразу заинтересовались его потенциалом. Сегодня этот интерес проявляется в уникальном поддомене нашей веб-платформы https://vr.with.in/ . Любой, у кого есть браузер с поддержкой VR, может зайти на сайт, нажать кнопку и надеть гарнитуру, чтобы погрузиться в наше портфолио VR-фильмов.

Сегодня это включает, помимо прочего, Chrome в Daydream View. Информацию о вашем устройстве и головном дисплее можно найти на https://webvr.info/ .

Как и другие среды рендеринга, специфичные для виртуальной реальности, Интернет преимущественно полагается на трехмерное представление сцены. В этой сцене есть камера, ваша перспектива и любое количество объектов. Чтобы управлять этой сценой, камерой и объектами, мы используем библиотеку Three.js , которая использует элемент <canvas> для передачи рендеринга на графический процессор вашего компьютера. Существует множество полезных дополнений Three.js, которые сделают вашу сцену доступной для просмотра в WebVR. Два основных — это THREE.VREffect для создания области просмотра для каждого глаза и THREE.VRControls для убедительной трансляции перспективы (например, вращения и положения головного дисплея) в вашу сцену. Есть много примеров того, как это реализовать. Ознакомьтесь с примерами Three.js WebVR , чтобы узнать, как начать работу.

По мере дальнейшего изучения WebVR мы столкнулись с проблемой. Если мы посмотрим на содержимое Интернета, текст станет его неотъемлемой частью. Хотя большая часть нашего контента основана на видео, если вы зайдете на сайт Within, контент будет окружен текстом; Пользовательский интерфейс и дополнительная информация о фильме или связанных с ним фильмах состоят из текста. Более того, весь этот текст создается в DOM. Наши исследования WebVR и https://vr.with.in/ находятся в <canvas> .

Текст, используемый в WebVRТекст, используемый в WebVR
Текст, используемый в WebVR для vr.with.in

Какие у меня есть варианты?

К счастью, работа над тем, чтобы это стало возможным, ведется. Фактически, в ходе нашего исследования мы нашли ряд эффективных способов визуализации текста в трехмерной среде с помощью элемента <canvas> . Ниже приведена таблица из нескольких найденных нами, отмеченных плюсами и минусами для каждого:

Независимый от разрешения Типографские особенности Производительность Простота реализации
2D-текст на холсте Да Да Да
Триангулированный векторный текст Да Да
Выдавленный 3D-текст Да
Текст растрового изображения поля расстояния со знаком Да Да Да

Наше решение: растровый шрифт SDF

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

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

Рабочий процесс преобразования шрифта в растровое изображение SDF
Рабочий процесс преобразования шрифта в растровое изображение SDF

В растровых шрифтах на каждый символ используется один квадрат (два треугольника), поэтому они используют меньше геометрии и работают лучше, чем триангулированные векторы . Они по-прежнему основаны на растре, поскольку используют спрайт карты текстуры, но с шейдером SDF они в основном не зависят от разрешения, поэтому выглядят лучше, чем текстура 2D-холста. Three-bmfont-text Мэтта ДеЛорье также включает в себя надежные типографские функции для переноса текста, межбуквенного интервала, высоты строки и выравнивания. Перелив не отсекается. Размер шрифта контролируется посредством масштаба. Мы выбрали этот путь, потому что он дает нам лучшие варианты дизайна, сохраняя при этом производительность. К сожалению, реализовать это оказалось не так просто, поэтому мы пройдемся по шагам в надежде помочь коллегам-разработчикам, работающим в WebVR.

1. Создайте растровый шрифт (.png + .fnt).

Интерфейс Иеро
Интерфейс Иеро
Вывод Hiero (растровый PNG и файл .fnt)Вывод Hiero (растровый PNG и файл .fnt)
Вывод Hiero (растровый PNG и файл .fnt)

Hiero — это инструмент для упаковки растровых шрифтов, работающий на Java. Документация Hiero на самом деле не объясняет, как запустить его, не пройдя сложный процесс сборки. Сначала установите Java, если вы еще этого не сделали. Затем, если двойной щелчок по файлу runnable-hiero.jar не открывает Hiero, попробуйте запустить его с помощью этой команды в консоли:

java -jar runnable-hiero.jar

После запуска Hiero откройте настольный шрифт .ttf или .otf, введите любые дополнительные символы, которые вы хотите включить, измените рендеринг на Java, чтобы включить эффекты, увеличьте размер, чтобы ваши символы заполняли весь квадрат кэша глифов, добавьте поле расстояния. эффекта, отрегулируйте масштаб и распространение поля расстояний. Значение масштаба аналогично разрешению. Чем оно выше, тем менее размытым будет изображение, но тем больше времени потребуется Hiero для рендеринга предварительного просмотра. Затем сохраните растровый шрифт. Он генерирует растровый шрифт, состоящий из изображения .png и файла описания шрифта AngelCode .fnt.

2. Преобразование AngelCode в JSON

Теперь, когда растровый шрифт создан, нам нужно загрузить его в наше javascript-приложение с помощью пакета npm load-bmfont Мэтта ДеЛорье.

Мы могли бы обозревать load-bmfont и использовать его во внешнем интерфейсе, но вместо этого мы собираемся запустить load-bmfont.js с Node, чтобы преобразовать и сохранить AngelCode .fnt Hiero в файл .json :

npm install
node load-bmfont.js
Пример вывода JSON
Пример вывода JSON

Теперь мы можем обойти load-bmfont и просто выполнить запрос XHR (XMLHttpRequest) к файлу шрифта .json.

var r = new XMLHttpRequest();
r.open('GET', 'fonts/roboto/bitmap/roboto-bold.json');

r.onreadystatechange = function() {
    if (r.readyState === 4 && r.status === 200) {
    setup(JSON.parse(r.responseText));
    }
};

r.send();

function setup(font) {
    // pass font into TextBitmap object
}

3. Просмотрите три-bmfont-text

Как только мы загрузим шрифт, обо всем остальном позаботится текст Мэтта Three-bmfont-text. Поскольку мы не используем Node для нашего собственного приложения, мы собираемся преобразовать файл Three-bmfont-text.js в пригодный для использования файл Three-bmfont-text-bundle.js.

npm install -g browserify
browserify three-bmfont-text.js -o three-bmfont-text-bundle.js

4. SDF-шейдер

Отрегулируйте ползунки afwidth и порог в vr.with.in/archive/text-sdf-bitmap/ , чтобы увидеть влияние шейдера поля расстояния со знаком.

5. Использование

Для удобства я создал класс-оболочку TextBitmap для браузерного текста Three-bmfont-text.

Text-sdf-bitmap в действии
Text-sdf-bitmap в действии
<script src="three-bmfont-text-bundle.js"></script>
<script src="sdf-shader.js"></script>
<script src="text-bitmap.js"></script>

Создайте запрос XHR для файла шрифта .json и создайте текстовый объект в обратном вызове:

var bmtext = new TextBitmap({ options });

Чтобы изменить текст:

bmtext.text = 'The quick brown fox jumps over the lazy dog.';

scene.add( bmtext.group );
hitBoxes.push( bmtext.hitBox );

PNG растрового шрифта загружается с помощью THREE.TextureLoader в text-bitmap.js.

TextBitmap также включает в себя невидимый хитбокс для взаимодействия с помощью Raycast Three.js через мышь, камеру или контроллеры движения с ручным отслеживанием, такие как Oculus Touch или контроллеры Vive. Размер хитбокса автоматически обновляется при изменении параметров текста.

Bmtext.group добавляется в сцену Three.js. Если вам нужен доступ к дочерним элементам/Object3D, граф сцены для текста выглядит так:

Схема файловой системы

6. Уменьшите json и измените xoffsets.

В текстовом формате gif

Если кернинг не работает, возможно, вам придется отредактировать смещения x в файле json. Вставьте JSON в Jsbeautifier.org , чтобы получить неминифицированную версию файла.

Xoffset — это, по сути, глобальный кернинг для одного символа. Кернинг предназначен для двух конкретных символов, которые появляются рядом друг с другом. Значения по умолчанию в массиве кернинга на самом деле не имеют значения, и редактировать их было бы слишком утомительно, поэтому вы можете очистить этот массив, чтобы уменьшить размер файла json. Затем отредактируйте смещения x для кернинга.

Сначала вам нужно выяснить, какие символы соответствуют идентификатору символа в json. В Three-bmfont-text-bundle.js вставьте console.log после строки 240:

    var id = text.charCodeAt(i)
    // console.log(id);

Затем введите текстовое поле dat.gui на https://vr.with.in/archive/text-sdf-bitmap/ и проверьте консоль, чтобы найти соответствующий идентификатор персонажа.

Например, в нашем растровом шрифте буква «j» постоянно находится слишком далеко вправо. Его идентификатор символа — 106. Итак, найдите "id": 106 в json и измените его xoffset с -1 на -10.

7. Планировка

Если у вас есть несколько блоков текста и вы хотите, чтобы он перемещался сверху вниз, как HTML, все необходимо позиционировать вручную, аналогично абсолютному позиционированию каждого элемента dom самостоятельно с помощью CSS. Можете ли вы представить себе, как это можно сделать с помощью CSS?

    * { position: absolute; }

Вот что такое макет текста в 3D. В подробном представлении: заголовок, автор, описание и продолжительность — это каждый новый объект TextBitmap со своими собственными стилями, цветом, масштабом и т. д.:

3d макет
author.group.position.y = title.group.position.y - title.height - padding;
description.group.position.y = author.group.position.y - author.height - padding;
duration.group.position.y = description.group.position.y - description.height - padding;

При этом предполагается, что локальное начало каждой группы TextBitmap вертикально выровнено с верхом сетки TextBitmap (см. центрирование в обновлении text-bitmap.js ). Если вы позже измените текст для любого из этих объектов и высота этого объекта изменится, вам также потребуется пересчитать эти позиции. Здесь изменяется только положение текста по оси Y, но одна из возможностей работы в 3D заключается в том, что мы можем толкать и тянуть текст в направлении z, а также вращать вокруг осей x, y и z.

Заключение

Тексту и макету в WebVR предстоит пройти долгий путь, прежде чем они станут такими же простыми и широко используемыми, как HTML и CSS. Но работающие решения существуют, и вы можете сделать гораздо больше с помощью WebVR, чем с традиционной веб-страницей HTML. WebVR существует сегодня. Вероятно, завтра появятся инструменты получше. А пока пробуйте и экспериментируйте. Разработка без универсальной структуры приводит к созданию более уникальных проектов, и это интересно.