Rendering del testo in WebVR

Nei dettagli

Visualizza il sito

All'interno (https://with.in/) è presente una piattaforma per lo storytelling nella realtà virtuale. Quando il team ha sentito parlare di WebVR nel 2015, ci siamo subito interessati al suo potenziale. Oggi, questo interesse si manifesta in un sottodominio unico della nostra piattaforma web, https://vr.with.in/. Chiunque disponga di un browser che supporta la VR può visitare il sito, fare clic su un pulsante e indossare un visore per immergersi nel nostro portafoglio di film VR.

Attualmente è incluso, a titolo esemplificativo, Chrome su Daydream View. Per informazioni sul dispositivo e sul display montato sulla testa, visita la pagina https://webvr.info/.

Come altri ambienti di rendering specifici per realtà virtuale, il web si basa prevalentemente su una rappresentazione tridimensionale di una scena. Questa scena include una fotocamera, la tua prospettiva e un numero qualsiasi di oggetti. Per gestire meglio la scena, la videocamera e gli oggetti, utilizziamo una libreria chiamata Three.js che sfrutta l'elemento <canvas> per eseguire il rendering nella GPU del computer. Esistono molti componenti aggiuntivi Three.js utili per rendere visibile la scena in WebVR. I due principali sono THREE.VREffect per creare un'area visibile per ogni occhio e THREE.VRControls per tradurre la prospettiva (ad esempio la rotazione e la posizione del display montato sulla testa) in modo convincente nella scena. Ci sono molti esempi di come implementare questa strategia. Per iniziare, consulta gli esempi di WebVR Three.js.

Mentre continuavamo a esplorare WebVR, abbiamo riscontrato un problema. Se guardiamo i contenuti del web, il testo è parte integrante di questo. Sebbene la maggior parte dei nostri contenuti sia basata su video, se visiti il testo All'interno del sito che circonda i contenuti, l'interfaccia utente e le informazioni aggiuntive su un film o su film correlati sono tutte compilate con testo. Inoltre, tutto questo testo viene creato nel DOM. Le nostre esplorazioni WebVR e https://vr.with.in/ sono tutte in <canvas>.

Testo utilizzato in WebVR Testo utilizzato in WebVR
Testo utilizzato in WebVR per vr.with.in

Quali sono le opzioni a mia disposizione?

Fortunatamente, stiamo lavorando per rendere possibile tutto ciò. Infatti, nella nostra ricerca abbiamo trovato una serie di modi efficaci per visualizzare il testo in un ambiente tridimensionale su un elemento <canvas>. Qui sotto trovi una serie di pro e contro:

Indipendente dalla risoluzione Elementi tipografici Esibizione Facilità di implementazione
Testo canvas 2D
Testo vettoriale tridimensionale
Testo 3D estruso
Testo bitmap del campo distanza firmato

La nostra decisione: carattere bitmap SDF

La tela 2D con ctx.fillText() consente di utilizzare il testo a capo, l'interlinea e l'altezza di riga, ma l'overflow viene tagliato e il testo viene sfocato se aumenti molto lo zoom. Potresti aumentare le dimensioni della texture della tela, ma potresti raggiungere un limite superiore di dimensioni della texture o risentirne le prestazioni se la texture è troppo grande.

Il testo 3D estruso è essenzialmente uguale al testo vettoriale triangolare, ma con profondità e probabilmente una smussatura, in modo da avere una geometria almeno doppia. Entrambi potrebbero funzionare a piccole dosi per titoli o loghi, ma non funzionare altrettanto bene per grandi quantità di testo e nessuno dei due ha caratteristiche tipografiche.

Flusso di lavoro bitmap da carattere a SDF
Flusso di lavoro bitmap da caratteri a SDF

I caratteri bitmap utilizzano un quad (due triangoli) per carattere, quindi utilizzano meno geometria e offrono prestazioni migliori rispetto ai vettori triangolari. Sono comunque basati sul raster poiché utilizzano uno sprite di mappa texture, ma con uno sprite SDF sono sostanzialmente indipendenti dalla risoluzione, quindi hanno un aspetto più bello rispetto a una texture su tela 2D. Il testo con tre bmfont-text di Matt DesLauriers include anche funzionalità tipografiche affidabili per il testo a capo, l'interlinea, l'altezza di riga e l'allineamento. L'overflow non viene tagliato. La dimensione dei caratteri viene controllata su scala. Abbiamo scelto questa strada perché ci ha offerto le migliori opzioni di design senza rinunciare alle prestazioni. Sfortunatamente, l'implementazione non è stata così semplice, quindi esamineremo i passaggi nella speranza di aiutare i colleghi sviluppatori che lavorano in WebVR.

1. Genera un carattere bitmap (.png + .fnt)

Interfaccia Hiero
Interfaccia Hiero
Output Hiero (file PNG bitmap e .fnt) Output Hiero (file PNG bitmap e .fnt)
Output Hiero (file PNG bitmap e file .fnt)

Hiero è uno strumento per la creazione di pacchetti di caratteri bitmap eseguito con Java. La documentazione di Hiero non spiega come eseguirlo senza passare attraverso un complicato processo di compilazione. Innanzitutto, installa Java se non l'hai ancora fatto. Quindi, se fai doppio clic sul file runnable-hiero.jar non apre Hiero, prova a eseguirlo nella console con questo comando:

java -jar runnable-hiero.jar

Quando Hiero è in esecuzione, apri un carattere desktop .ttf o .otf, inserisci eventuali caratteri aggiuntivi che vuoi includere, modifica il rendering in Java per attivare gli effetti, aumenta le dimensioni in modo che i caratteri riempiano l'intero quadrato della cache del glifo, aggiungi un effetto di campo relativo alla distanza, regola la scala e la distribuzione del campo distanza. Il valore di scala è come una risoluzione. Più alto è il livello, meno sfocato sarà, ma più tempo impiegherà Hiero per visualizzare l'anteprima. Poi salva il carattere bitmap. Genera un carattere bitmap composto da un'immagine .png e un file di descrizione del carattere .fnt AngelCode.

2. Converti AngelCode in JSON

Ora che il carattere bitmap è stato generato, dobbiamo caricarlo nella nostra app JavaScript con il pacchetto npm di Matt DesLauriers.

Potremmo browserificare il valore Load-bmfont e utilizzarlo sul front-end, ma invece eseguiremo load-bmfont.js con Node per convertire e salvare il file .fnt AngelCode di Hiero in un file.json:

npm install
node load-bmfont.js
Esempio di JSON di output
Esempio di JSON di output

Ora possiamo ignorare upload-bmfont ed eseguire semplicemente una richiesta XHR (XMLHttpRequest) sul file del carattere .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. Testo con tre caratteri bmfont da Browserify

Una volta caricato il carattere, al resto ci pensa il testo con tre caratteri di carattere di Matt. Dal momento che non utilizziamo Node per la nostra app, passiamo a browserify Three-bmfont-text.js in un file three-bmfont-text-bundle.js utilizzabile.

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

4. Shader SDF

Regola i dispositivi di scorrimento afwidth e threshold su vr.with.in/archive/text-sdf-bitmap/ per vedere l'effetto dello ombreggiatore campo distanza firmato.

5. Utilizzo

Per praticità, ho creato una classe wrapper TextBitmap per il testo tre-bmfont-text browserificato.

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

Crea una richiesta XHR per il file del carattere .json e crea un oggetto di testo nel callback:

var bmtext = new TextBitmap({ options });

Per modificare il testo:

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

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

Il file .png del carattere bitmap viene caricato con THREE.TextureLoader in text-bitmap.js

TextBitmap include anche una hitbox invisibile per l'interazione trip.js raycast tramite mouse, fotocamera o controller di movimento con rilevamento della mano come Oculus Touch o i controller Vive. Le dimensioni della hitbox si aggiornano automaticamente quando modifichi le opzioni di testo.

Bmtext.group viene aggiunto alla scena third.js. Se devi accedere agli oggetti secondari /Object3D, il grafico delle scene per il testo sarà simile al seguente:

Diagramma del file system

6. Riunisci le dimensioni del file json e modifica gli xoffset

All&#39;interno di una GIF di testo

Se la crenatura è irregolare, potresti dover modificare gli xoffset nel file json. Incolla il file json in Jsbeautifier.org per ottenere una versione unificata del file.

Lo xoffset è essenzialmente la crenatura globale di un carattere. La crenatura si riferisce a due caratteri specifici che vengono visualizzati uno accanto all'altro. I valori predefiniti nell'array di crenatura in realtà non fanno alcuna differenza e sarebbe troppo noioso per modificarli, quindi puoi svuotare l'array per ridurre le dimensioni del file del json. Poi modifica xoffsets per la crenatura.

Per prima cosa devi capire quali caratteri associare a quale ID carattere nel json. In three-bmfont-text-bundle.js, inserisci console.log dopo la riga 240:

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

Poi digita nel campo di testo dat.gui su https://vr.with.in/archive/text-sdf-bitmap/ e controlla nella console l'ID corrispondente di un carattere.

Ad esempio, nel carattere bitmap, "j" è costantemente troppo a destra. L'ID carattere è 106. Quindi, trova "id": 106 nel file JSON e modifica il relativo xoffset da -1 a -10.

7. Layout

Se hai più blocchi di testo e vuoi che fluiscano dall'alto verso il basso come in HTML, tutto deve essere posizionato manualmente, come per il posizionamento assoluto di ogni elemento dom con CSS. Potete immaginare di farlo in CSS?

    * { position: absolute; }

Questo è il layout del testo in 3D. Nella visualizzazione dettagliata: titolo, autore, descrizione e durata sono entrambi nuovi oggetti TextBitmap con stili, colore, scala e così via specifici:

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

Questo presuppone che l'origine locale di ciascun gruppo TextBitmap sia allineata verticalmente con la parte superiore del mesh TextBitmap (vedi la centratura in text-bitmap.js Update). Se in seguito modifichi il testo di uno di questi oggetti e l'altezza di quell'oggetto cambia, dovrai ricalcolare anche queste posizioni. Qui viene modificata solo la posizione y del testo, ma un'opportunità per lavorare in 3D è che possiamo spostare e tirare il testo in direzione z, nonché ruotare intorno agli assi x, y e z.

Conclusione

Il testo e il layout in WebVR hanno molta strada da fare prima di diventare semplici e ampiamente utilizzati come HTML e CSS. Esistono però soluzioni funzionanti e in WebVR puoi fare molto di più di quanto non con una pagina web HTML tradizionale. WebVR esiste oggi. Probabilmente domani ci saranno strumenti migliori. Fino ad allora, provala e sperimenta. Lo sviluppo senza un framework onnipresente porta a progetti più unici, ed è entusiasmante.