Text in WebVR rendern

Im Detail

Website ansehen

Innerhalb von (https://with.in/) gibt es eine Plattform für Virtual Reality-Storytelling. Als das Team 2015 von WebVR erfuhr, waren wir sofort an seinem Potenzial interessiert. Heute zeigt sich dieses Interesse in einer eindeutigen Subdomain unserer Webplattform https://vr.with.in/. Jeder mit einem VR-fähigen Browser kann die Website aufrufen, auf eine Schaltfläche klicken und ein Headset aufsetzen, um in unser Portfolio von VR-Filmen einzutauchen.

Das betrifft unter anderem auch Chrome auf Daydream View. Informationen zu Ihrem Gerät und dem Head-Mounted Display finden Sie unter https://webvr.info/.

Wie andere für Virtual Reality spezifische Rendering-Umgebungen, nutzt das Web vorwiegend die dreidimensionale Darstellung einer Szene. Diese Szene enthält eine Kamera, Ihre Perspektive und eine beliebige Anzahl von Objekten. Um diese Szene, Kamera und Objekte zu verwalten, verwenden wir eine Bibliothek namens Three.js, die das <canvas>-Element nutzt, um das Rendering auf der GPU Ihres Computers zu übernehmen. Es gibt viele nützliche Three.js-Add-ons, mit denen Sie Ihre Szene in WebVR sichtbar machen können. Die beiden wichtigsten sind THREE.VREffect zum Erstellen eines Darstellungsbereichs für jedes Auge und THREE.VRControls für die überzeugende Übersetzung der Perspektive, z. B. der Drehung und Position des Head-Mounted Displays. Es gibt viele Beispiele für die Implementierung. Sehen Sie sich für den Einstieg die Three.js WebVR-Beispiele an.

Bei der Erkundung von WebVR sind wir auf ein Problem gestoßen. Wenn wir uns die Inhalte des Webs ansehen, ist Text ein integraler Bestandteil. Die meisten unserer Inhalte sind videobasiert. Wenn Sie jedoch die Seite Auf der Website aufrufen, umgibt der Text den Inhalt; die Benutzeroberfläche und zusätzliche Informationen zu einem Film oder ähnlichen Filmen bestehen allesamt aus Text. Außerdem wird der gesamte Text im DOM erstellt. Unsere WebVR-Untersuchungen und https://vr.with.in/ sind alle in <canvas>.

In WebVR verwendeter Text In WebVR verwendeter Text
In WebVR verwendeter Text für vr.with.in

Welche Optionen habe ich?

Glücklicherweise wird daran gearbeitet, dies zu ermöglichen. In unserer Forschung haben wir eine Reihe effektiver Möglichkeiten gefunden, Text in einer dreidimensionalen Umgebung auf einem <canvas>-Element zu rendern. Die folgende Matrix enthält einige Vor- und Nachteile:

Auflösungsunabhängig Typografische Merkmale Leistung Einfache Implementierung
2D-Canvas-Text Ja Ja Ja
Triangulierter Vektortext Ja Ja
Extrudierter 3D-Text Ja
Bitmaptext des Felds für den signierten Abstand Ja Ja Ja

Unsere Entscheidung: Bitmapschrift in SDF

Auf dem 2D-Canvas mit ctx.fillText() können Textumbrüche, Abstände zwischen Buchstaben und Zeilenhöhe verwendet werden, allerdings wird der Überlauf abgeschnitten und der Text wird verschwommen, wenn du viel heranzoomst. Sie können die Größe der Canvas-Textur erhöhen, aber möglicherweise einen oberen Grenzwert für die Texturgröße erreichen oder die Leistung beeinträchtigen, wenn die Textur zu groß ist.

Extrudierter 3D-Text ist im Wesentlichen mit trianguliertem Vektortext identisch, hat jedoch Tiefe und möglicherweise eine Abschrägung, sodass er mindestens doppelt so viel Geometrie hat. Beide Optionen eignen sich zwar in kleinen Mengen für Titel oder Logos, eignen sich aber nicht für große Textmengen und haben keine typografischen Merkmale.

Schriftart für SDF-Bitmap-Workflow
Workflow von Schriftart in SDF-Bitmap

Bitmap-Schriftarten verwenden ein Viereck (zwei Dreiecke) pro Zeichen, wodurch sie weniger Geometrie benötigen und eine bessere Leistung als triangulierte Vektoren bieten. Sie basieren immer noch auf Rastern, da sie Texturkarten-Sprite verwenden. Mit einem SDF-Shader sind sie jedoch im Wesentlichen auflösungsunabhängig und sehen daher besser als eine 2D-Canvas-Textur aus. Die Three-bmfont-text-Datei von Matt DesLauriers enthält außerdem zuverlässige typografische Merkmale für den Textumbruch, den Buchstabenabstand, die Zeilenhöhe und die Ausrichtung. Der Überlauf wird nicht abgeschnitten. Die Schriftgröße wird über die Skalierung gesteuert. Wir haben uns für diese Route entschieden, weil wir damit die besten Designoptionen erhalten und gleichzeitig leistungsstark bleiben. Leider war die Implementierung nicht so einfach. Deshalb werden wir die einzelnen Schritte in der Hoffnung erläutern, dass wir anderen Entwicklern bei der Arbeit mit WebVR helfen können.

1. Bitmapschriftart (PNG + FNT) erstellen

Hiero-Oberfläche
Hiero-Oberfläche
Hiero-Ausgabe (Bitmap-PNG- und FNT-Datei) Hiero-Ausgabe (Bitmap-PNG- und FNT-Datei)
Hiero-Ausgabe (Bitmap-PNG- und FNT-Datei)

Hiero ist ein Tool zum Packen von Bitmap-Schriftarten, das mit Java ausgeführt wird. Die Hiero-Dokumentation erklärt nicht wirklich, wie sie ausgeführt wird, ohne einen komplizierten Build-Prozess zu durchlaufen. Installieren Sie zuerst Java, falls Sie dies noch nicht getan haben. Wenn Hiero durch Doppelklicken auf „runnable-hiero.jar“ nicht geöffnet wird, führen Sie die Datei mit dem folgenden Befehl in der Console aus:

java -jar runnable-hiero.jar

Sobald Hiero ausgeführt wird, öffnen Sie eine .ttf- oder .otf-Desktopschrift, geben Sie alle zusätzlichen Zeichen ein, die verwendet werden sollen. Ändern Sie das Rendering in Java, um Effekte zu aktivieren. Erhöhen Sie die Größe, sodass die Zeichen das gesamte Glyph-Cache-Quadrat ausfüllen, fügen Sie einen Entfernungsfeldeffekt hinzu und passen Sie die Größe und Verteilung des Entfernungsfelds an. Der Skalierungswert ist wie eine Auflösung. Je höher sie ist, desto weniger verschwommen wird sie, aber desto länger dauert es, bis Hiero die Vorschau gerendert wird. Speichern Sie dann Ihre Bitmap-Schriftart. Dabei wird eine Bitmapschriftart generiert, die aus einem PNG-Bild und einer AngelCode-Fnt-Beschreibungsdatei besteht.

2. AngelCode in JSON konvertieren

Nachdem die Bitmapschriftart generiert wurde, müssen wir sie mit dem npm-Paket "load-bmfont" von Matt DesLauriers in unsere JavaScript-Anwendung laden.

Wir könnten „load-bmfont“ mit Browser verknüpfen und im Front-End verwenden. Stattdessen führen wir aber load-bmfont.js mit Node aus, um die Hiero-AngelCode-Datei „.fnt“ zu konvertieren und in einer .json-Datei zu speichern:

npm install
node load-bmfont.js
Beispiel für eine JSON-Ausgabe
Beispiel für eine JSON-Ausgabe

Jetzt können wir „load-bmfont“ umgehen und einfach eine XHR-Anfrage (XMLHttpRequest) für die Schriftartdatei .json ausführen.

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. Browserify (drei-bmfont-text)

Sobald wir die Schriftart geladen haben, kümmert sich Matts drei-bmfont-text um den Rest. Da wir Node.js nicht für unsere eigene Anwendung verwenden, wandeln wir den Browserify von three-bmfont-text.js in ein nutzbares three-bmfont-text-bundle.js um.

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

4. SDF-Shader

Passen Sie die Schieberegler afwidth und threshold auf vr.with.in/archive/text-sdf-bitmap/ an, um die Auswirkungen des Feld-Shaders mit signierter Entfernung zu sehen.

5. Nutzung

Zur Vereinfachung habe ich eine TextBitmap-Wrapper-Klasse für das im Browser erstellte 3-bmfont-text-Element erstellt.

Text-sdf-Bitmap in Aktion
Text-SDF-Bitmap in Aktion
<script src="three-bmfont-text-bundle.js"></script>
<script src="sdf-shader.js"></script>
<script src="text-bitmap.js"></script>

Erstellen Sie eine XHR-Anfrage für die .json-Schriftartdatei und ein Textobjekt im Callback:

var bmtext = new TextBitmap({ options });

So ändern Sie den Text:

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

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

Die PNG-Datei der Bitmap-Schriftart wird mit THREE .TextureLoader in "text-bitmap.js" geladen.

TextBitmap enthält auch eine unsichtbare Hitbox für drei.js-Raycast-Interaktionen über eine Maus, eine Kamera oder von Hand verfolgte Bewegungssteuerungen wie Oculus Touch oder die Vive-Controller. Die Größe der Hitbox wird automatisch aktualisiert, wenn Sie die Textoptionen ändern.

„Bmtext.group“ wird der „Three.js-Szene“ hinzugefügt. Wenn Sie auf die untergeordneten Elemente/Object3D-Elemente zugreifen müssen, sieht das Szenendiagramm für den Text so aus:

Dateisystemdiagramm

6. json komprimieren und xoffsets ändern

GIF innerhalb des Textes

Wenn die Unterschneidung nicht funktioniert, müssen Sie möglicherweise die xoffsets in der JSON-Datei bearbeiten. Fügen Sie die JSON-Datei in Jsbeautifier.org ein, um eine nicht komprimierte Version der Datei zu erhalten.

Der xoffset ist im Wesentlichen die globale Unterschneidung für ein Zeichen. Unterschneidung ist für zwei bestimmte Zeichen vorgesehen, die nebeneinander erscheinen. Die Standardwerte im Unterschneidungsarray spielen eigentlich keinen Unterschied und es wäre zu mühsam zu bearbeiten, sodass Sie dieses Array leeren können, um die Dateigröße der JSON-Datei zu verringern. Bearbeiten Sie dann die xoffsets für die Unterschneidung.

Zuerst müssen Sie herausfinden, welche Zeichen in der JSON-Datei zu welcher Zeichen-ID gehören. Fügen Sie in three-bmfont-text-bundle.js nach Zeile 240 console.log ein:

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

Geben Sie dann in das Textfeld „dat.gui“ auf https://vr.with.in/archive/text-sdf-bitmap/ ein und suchen Sie in der Konsole nach der entsprechenden Zeichen-ID.

In unserer Bitmapschriftart steht „j“ beispielsweise durchgängig zu weit rechts. Die Zeichen-ID lautet 106. Suchen Sie daher in der JSON-Datei nach "id": 106 und ändern Sie den xoffset-Wert von -1 in -10.

7. Layout

Wenn Sie mehrere Textblöcke haben, die wie HTML von oben nach unten verlaufen sollen, muss alles manuell positioniert werden, ähnlich wie bei der absoluten Positionierung jedes dom-Elements mit CSS. Können Sie sich das in CSS vorstellen?

    * { position: absolute; }

So sieht das Textlayout in 3D aus. In der Detailansicht sind Titel, Autor, Beschreibung und Dauer jeweils ein neues TextBitmap-Objekt mit eigenen Stilen, Farben, Maßstabs usw.:

3D-Layout
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;

Dabei wird davon ausgegangen, dass der lokale Ursprung jeder TextBitmap-Gruppe vertikal am oberen Rand des TextBitmap-Netzes ausgerichtet ist (siehe Zentrierung in text-bitmap.js-Update). Wenn Sie später den Text für eines dieser Objekte ändern und sich die Höhe dieses Objekts ändert, müssen Sie diese Positionen ebenfalls neu berechnen. Hier wird nur die Y-Position des Textes geändert. Eine Möglichkeit der Arbeit in 3D besteht jedoch darin, den Text in Z-Richtung zu verschieben und zu ziehen sowie um die x-, y- und z-Achse zu drehen.

Fazit

Text und Layout in WebVR haben noch einen langen Weg zurückgelegt, bevor sie so einfach und weit verbreitet sind wie HTML und CSS. Es gibt jedoch funktionierende Lösungen und Sie können mit WebVR deutlich mehr machen als mit einer herkömmlichen HTML-Webseite. WebVR gibt es heute. Wahrscheinlich wird es morgen bessere Tools geben. Probieren Sie es bis dahin und probieren Sie es aus. Die Entwicklung ohne ein allgegenwärtiges Framework führt zu einzigartigen Projekten, und das ist aufregend.