Dans (https://with.in/) se trouve une plate-forme de storytelling en réalité virtuelle. Ainsi, lorsque l'équipe a entendu parler de WebVR en 2015, nous nous sommes immédiatement intéressés à son potentiel. Aujourd'hui, cet intérêt se manifeste dans un sous-domaine unique de notre plate-forme Web, https://vr.with.in/. Toute personne disposant d'un navigateur compatible RV peut accéder au site, cliquer sur un bouton et mettre un casque pour se plonger dans notre gamme de films en réalité virtuelle.
Aujourd'hui, cela inclut, sans s'y limiter, Chrome sur Daydream View. Pour en savoir plus sur votre appareil et votre visiocasque, consultez la page https://webvr.info/.
Comme d'autres environnements de rendu spécifiques à la réalité virtuelle, le Web repose principalement sur une représentation en trois dimensions d'une scène. Cette scène comporte une caméra, votre perspective et un nombre illimité d'objets. Pour faciliter la gestion de cette scène, de la caméra et des objets, nous utilisons une bibliothèque appelée Three.js qui exploite l'élément <canvas>
pour lancer le rendu sur le GPU de votre ordinateur. Il existe de nombreux modules complémentaires Three.js utiles pour rendre votre scène visible dans WebVR. Les deux principaux sont THREE.VREffect pour créer une fenêtre d'affichage pour chaque œil et THREE.VRControls pour traduire la perspective (par exemple, la rotation et la position de l'écran visé) de manière convaincante dans votre scène. Il existe de nombreux exemples de mise en œuvre. Pour vous lancer, consultez les exemples WebVR de Three.js.
En explorant WebVR plus en détail, nous avons rencontré un problème. Si nous regardons le contenu du Web, le texte en fait partie intégrante. Bien que la majorité de notre contenu soit basé sur une vidéo, si vous accédez à la section Dans le site, le contenu est placé au centre du contenu. L'interface utilisateur et les informations supplémentaires sur un film ou des films similaires sont tous créés avec du texte. De plus, tout ce texte est créé dans le DOM. Nos explorations WebVR et https://vr.with.in/ sont toutes disponibles dans <canvas>
.
Quelles sont mes options ?
Heureusement, nous mettons tout en œuvre pour rendre cela possible. En fait, nos recherches ont révélé plusieurs méthodes efficaces pour afficher du texte dans un environnement tridimensionnel sur un élément <canvas>
. Vous trouverez ci-dessous une matrice de quelques-uns de ces points, avec leurs avantages et leurs inconvénients respectifs:
Indépendant de la résolution | Caractéristiques typographiques | Performances | Facilité d'implémentation | |
---|---|---|---|---|
Texte du canevas 2D | Oui | Oui | Oui | |
Texte vectoriel tronqué | Oui | Oui | ||
Texte 3D extrudé | Oui | |||
Texte bitmap du champ de distance signé | Oui | Oui | Oui |
Notre décision: police bitmap SDF
Le canevas 2D avec ctx.fillText()
permet de renvoyer le texte à la ligne, d'espacer les lettres et de définir la hauteur des lignes, mais le dépassement est tronqué et le texte sera flou si vous faites un zoom avant trop important. Vous pouvez augmenter la taille de la texture du canevas, mais vous risquez d'atteindre une limite supérieure en termes de taille ou de performances si la texture est trop grande.
Le texte 3D extrudé est essentiellement identique au texte vectoriel triangulé, mais avec de la profondeur et éventuellement un biseau, il présente donc au moins deux fois plus de géométrie. L'une ou l'autre de ces méthodes peut fonctionner à faible dose pour les titres ou les logos, mais ne fonctionnerait pas aussi bien pour de grandes quantités de texte et aucune de ces deux méthodes n'a de caractéristiques typographiques.
Les polices bitmap utilisent un quad (deux triangles) par caractère. Elles utilisent donc moins de géométrie et offrent de meilleures performances que les vecteurs triangulés. Ils sont toujours basés sur une trame, car ils utilisent un lutin de map de texture, mais avec un nuanceur SDF, ils sont essentiellement indépendants de la résolution. Ils sont donc plus beaux qu'une texture de canevas 2D. Le texte three-bmfont de Matt DesLauriers inclut également des fonctionnalités typographiques fiables pour le retour à la ligne, l'espacement des lettres, la hauteur des lignes et l'alignement. Le dépassement n'est pas tronqué. La taille de la police est contrôlée par l'échelle. Nous avons choisi cette approche, car elle nous offre les meilleures options de conception tout en restant performants. Malheureusement, l'implémentation n'a pas été aussi facile à mettre en œuvre. Nous allons donc suivre la procédure dans l'espoir d'aider d'autres développeurs travaillant sur WebVR.
1. Générer une police bitmap (.png + .fnt)
Hiero est un outil d'empaquetage de polices bitmap qui s'exécute avec Java. La documentation de Hiero n'explique pas vraiment comment l'exécuter sans passer par un processus de compilation complexe. Tout d'abord, installez Java si ce n'est pas déjà fait. Ensuite, si le double-clic sur runnable-hiero.jar n'ouvre pas Hiero, essayez de l'exécuter à l'aide de la commande suivante dans la console:
java -jar runnable-hiero.jar
Une fois que Hiero est en cours d'exécution, ouvrez une police de bureau .ttf ou .otf, saisissez les caractères supplémentaires que vous souhaitez inclure, définissez le rendu sur Java pour activer les effets, augmentez la taille pour que vos caractères remplissent tout le carré du cache de glyphes, ajoutez un effet de champ de distance, ajustez l'échelle et l'étendue du champ de distance. La valeur d'échelle est semblable à une résolution. Plus cette valeur est élevée, moins l'image est floue, mais plus Hiero met du temps à afficher l'aperçu. Enregistrez ensuite votre police bitmap. Il génère une police bitmap composée d'une image .png et d'un fichier de description de police .fnt AngelCode.
2. Convertir le code AngelCode en JSON
Maintenant que la police bitmap a été générée, nous devons la charger dans notre application JavaScript avec le package npm load-bmfont de Matt DesLauriers.
Nous pourrions utiliser load-bmfont et l'utiliser sur l'interface, mais nous allons exécuter load-bmfont.js avec Node pour convertir le fichier AngelCode de Hiero et l'enregistrer en fichier .json:
npm install
node load-bmfont.js
Nous pouvons à présent contourner load-bmfont et effectuer simplement une requête XHR (XMLHttpRequest) sur le fichier de polices .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. Browserify three-bmfont-text
Une fois la police chargée, le three-bmfont-text de Matt se charge du reste. Comme nous n'utilisons pas Node pour notre propre application, nous allons browserify three-bmfont-text.js en un fichier three-bmfont-text-bundle.js utilisable
npm install -g browserify
browserify three-bmfont-text.js -o three-bmfont-text-bundle.js
4. Nuanceur de fichiers SDF
Ajustez les curseurs afwidth et threshold sur vr.with.in/archive/text-sdf-bitmap/ pour voir l'effet du nuanceur de champ de distance signé.
5. Utilisation
Pour plus de commodité, j'ai créé une classe de wrapper TextBitmap pour le three-bmfont-text de navigateurifié.
<script src="three-bmfont-text-bundle.js"></script>
<script src="sdf-shader.js"></script>
<script src="text-bitmap.js"></script>
Créez une requête XHR pour le fichier de police .json et créez un objet texte dans le rappel:
var bmtext = new TextBitmap({ options });
Pour modifier le texte:
bmtext.text = 'The quick brown fox jumps over the lazy dog.';
scene.add( bmtext.group );
hitBoxes.push( bmtext.hitBox );
Le fichier .png de la police bitmap est chargé par THREE.TextureLoader dans text-bitmap.js.
TextBitmap inclut également un masque de collision invisible pour les interactions raycast 3.js avec une souris, un appareil photo ou des contrôleurs de mouvement suivis manuellement, comme l'Oculus Touch ou les contrôleurs Vive. La taille du masque de collision est mise à jour automatiquement lorsque vous modifiez les options de texte.
Ajout de Bmtext.group à la scène three.js. Si vous devez accéder aux enfants/d'Object3D, le graphique de scène du texte se présente comme suit:
6. Supprimer la taille de JSON et modifier les xoffsets
Si le crénage est différent, vous devrez peut-être modifier les xoffsets dans le fichier JSON. Collez le fichier JSON dans Jsbeautifier.org pour obtenir une version non réduite du fichier.
Le xoffset est essentiellement un crénage global d'un caractère. Le crénage concerne deux caractères spécifiques qui apparaissent l'un à côté de l'autre. Les valeurs par défaut du tableau de crénage ne font pas de différence et il serait trop fastidieux à modifier. Vous pouvez donc vider ce tableau pour réduire la taille du fichier JSON. Modifiez ensuite les xoffsets pour le crénage.
Vous devez d'abord déterminer quels caractères correspondent à quel ID de caractère dans le fichier JSON. Dans three-bmfont-text-bundle.js, insérez console.log
après la ligne 240:
var id = text.charCodeAt(i)
// console.log(id);
Saisissez ensuite du texte dans le champ de texte dat.gui sur https://vr.with.in/archive/text-sdf-bitmap/, puis consultez la console pour trouver l'ID correspondant d'un personnage.
Par exemple, dans notre police bitmap, "j" est constamment trop à droite. Son ID de caractère est 106. Recherchez donc "id": 106
dans le fichier JSON et modifiez son xoffset de -1 à -10.
7. Mise en page
Si vous disposez de plusieurs blocs de texte et que vous souhaitez qu'ils s'affichent de haut en bas, comme avec le code HTML, tout doit être positionné manuellement, de la même manière que le positionnement absolu de chaque élément DoM avec CSS. Imaginez-vous faire cela en CSS ?
* { position: absolute; }
C'est à quoi ressemble la mise en page de texte en 3D. Dans la vue détaillée, le titre, l'auteur, la description et la durée sont chacun un nouvel objet TextBitmap avec leurs propres styles, couleurs, échelles, etc.:
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;
Cela suppose que l'origine locale de chaque groupe TextBitmap est alignée verticalement avec la partie supérieure du maillage TextBitmap (voir la section sur le centrage dans la mise à jour text-bitmap.js). Si, par la suite, vous modifiez le texte de l'un de ces objets et que la hauteur de cet objet change, vous devrez également recalculer ces positions. Ici, seule la position Y du texte est modifiée. Toutefois, pour travailler en 3D, vous pouvez pousser et extraire le texte dans la direction Z, et faire pivoter les axes X, Y et Z.
Conclusion
Dans WebVR, le texte et la mise en page ont encore beaucoup de chemin avant d'être aussi faciles à utiliser et aussi largement utilisés que HTML et CSS. Cependant, des solutions fonctionnelles existent, et vous pouvez faire bien plus dans WebVR qu'avec une page Web HTML traditionnelle. WebVR existe aujourd'hui. Il y aura probablement de meilleurs outils demain. En attendant, essayez-les et faites des tests. Développer sans framework omniprésent donne lieu à des projets plus uniques, et c'est passionnant.