内(https://with.in/)は、バーチャル リアリティにおけるストーリーテリングのプラットフォームです。そのため 2015 年に担当チームが WebVR の存在を知ったとき、私たちはその可能性にすぐに関心を示しました。現在、この関心は Google のウェブ プラットフォームの固有のサブドメイン https://vr.with.in/ に現れています。VR 対応ブラウザがあれば、誰でもサイトにアクセスし、ボタンをクリックし、ヘッドセットを装着して、VR 映画のポートフォリオに没入できます。
現在、Daydream View の Chrome が対象となりますが、これに限定されるものではありません。デバイスとヘッドマウント ディスプレイの詳細については、https://webvr.info/ をご覧ください。
他のバーチャル リアリティ固有のレンダリング環境と同様に、ウェブは主にシーンの 3 次元表現に依存しています。このシーンには、カメラ、視点、任意の数のオブジェクトが含まれます。このシーン、カメラ、オブジェクトを管理するために、Three.js というライブラリを使用します。このライブラリは、<canvas>
要素を利用して、パソコンの GPU にレンダリングをスローします。WebVR でシーンを表示可能にするために役立つ Three.js アドオンが多数用意されています。主な 2 つは、左右それぞれの目用にビューポートを作成する THREE.VREffect と、遠近(ヘッドマウント ディスプレイの回転や位置など)をシーンに納得させる THREE.VRControls です。これを実装する方法の例は数多くあります。開始方法については、Three.js WebVR の例をご覧ください。
WebVR について詳しく調べるうちに、ある問題に直面しました。ウェブのコンテンツを見ると、テキストは不可欠な要素です。Google のコンテンツの大部分は動画をベースにしていますが、[サイト内] というテキストがコンテンツを囲んでいます。映画や関連映画に関するユーザー インターフェースや追加情報はすべて、テキストで構成されています。さらに、このテキストはすべて DOM で作成されます。WebVR データ探索と https://vr.with.in/ はすべて <canvas>
にあります。
どのような選択肢がありますか?
幸い、これを可能にするための研究が行われています。実際、Google の調査では、<canvas>
要素上の 3 次元環境でテキストをレンダリングする効果的な方法が多数見つかりました。以下に、それぞれの長所と短所を示した表を示します。
解像度に依存しない | タイポグラフィ機能 | パフォーマンス | 実装の容易さ | |
---|---|---|---|---|
2D キャンバス テキスト | ○ | ○ | ○ | |
三角化されたベクトル テキスト | ○ | ○ | ||
押し出し成形された 3D テキスト | ○ | |||
符号付き距離フィールドのビットマップ テキスト | ○ | ○ | ○ |
Google の決定: SDF ビットマップ フォント
ctx.fillText()
を使用する 2D キャンバスでは、テキストの折り返し、文字間隔、行の高さを設定できますが、極端にズームインするとテキストがぼやけるため、はみ出した部分がカットされます。キャンバス テクスチャのサイズを大きくすることはできますが、テクスチャのサイズの上限に達したり、テクスチャが大きすぎるとパフォーマンスが低下したりする可能性があります。
押し出された 3D テキストは、三角形のベクター テキストと基本的に同じですが、奥行きがあり、場合によっては面取りがあるため、形状は少なくとも 2 倍になります。どちらのタイプも、タイトルやロゴには少量ですが、大量のテキストではうまく機能しません。また、どちらのタイプもタイポグラフィ機能を備えていません。
ビットマップ フォントでは文字ごとに 1 つのクワッド(2 つの三角形)を使用するため、三角形のベクターよりもジオメトリが少なく、パフォーマンスに優れています。テクスチャ マップ スプライトを使用するため、引き続きラスターベースですが、SDF シェーダーを使用すると、基本的に解像度に依存しないため、2D キャンバスのテクスチャよりもきれいに見えます。Matt DesLauriers の 3-bmfont-text には、テキストの折り返し、文字間隔、行の高さ、配置のための信頼性の高いタイポグラフィ機能も含まれています。はみ出しが途切れることはありません。フォントサイズはスケールで制御できます。パフォーマンスを維持しながらデザイン面での 最適な選択肢を提供できるからです残念ながら実装は簡単ではないため、WebVR で作業する他のデベロッパーを支援できるように、手順を説明します。
1. ビットマップ フォント(.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 に変換する
ビットマップ フォントが生成されたら、Matt DesLauriers の load-bmfont npm パッケージを使用して JavaScript アプリに読み込みます。
load-bmfont をブラウザ化してフロントエンドで使用できますが、代わりに Node で load-bmfont.js を実行し、Hiero の AngelCode .fnt を .json ファイルに変換して保存します。
npm install
node load-bmfont.js
これで、load-bmfont をバイパスして、.json フォント ファイルで XHR(XMLHttpRequest)リクエストを実行するだけで済むようになりました。
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 3-bmfont-text
フォントが読み込まれたら、Matt の 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 シェーダー
vr.with.in/archive/text-sdf-bitmap/ の afwidth スライダーと threshold スライダーを調整して、符号付き距離フィールド シェーダーの影響を確認します。
5. 使用状況
便宜上、ブラウザ化された three-bmfont-text 用の TextBitmap ラッパークラスを作成しました。
<script src="three-bmfont-text-bundle.js"></script>
<script src="sdf-shader.js"></script>
<script src="text-bitmap.js"></script>
.json フォント ファイルの XHR リクエストを作成し、コールバックでテキスト オブジェクトを作成します。
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 が、text-bitmap.js の THREE.TextureLoader を使用して読み込まれます。
TextBitmap には、マウス、カメラ、または Oculus Touch や Vive コントローラなどのハンドトラック型モーション コントローラを介して、3.js レイキャスト操作を行うための非表示ヒットボックスも含まれています。テキスト オプションを変更すると、ヒットボックスのサイズが自動更新されます。
Bmtext.group が three.js シーンに追加されます。子や Object3D にアクセスする場合、テキストのシーングラフは次のようになります。
6. JSON を非最小化して xoffset を変更する
カーニングがおかしい場合は、JSON 内の xoffset を編集する必要があるかもしれません。この JSON を Jsbeautifier.org に貼り付け、ファイルの非圧縮版を取得します。
xoffset は基本的に 1 文字に対するグローバル カーニングです。カーニングは、隣り合う 2 つの特定の文字を対象としています。カーニング配列のデフォルト値は実際には違いを生じず、編集が面倒なため、その配列を空にして json のファイルサイズを小さくすることができます。次に、カーニングの xoffset を編集します。
まず、json でどの文字がどの文字 ID に対応しているかを把握する必要があります。three-bmfont-text-bundle.js で、240 行目の後に console.log
を挿入します。
var id = text.charCodeAt(i)
// console.log(id);
次に、https://vr.with.in/archive/text-sdf-bitmap/ の dat.gui テキスト フィールドに入力し、コンソールで文字に対応する ID を探します。
たとえば、今回のビットマップ フォントでは「j」が常に右に離れすぎています。その文字 ID は 106 です。json で "id": 106
を見つけて、xoffset を -1 から -10 に変更します。
7. レイアウト
HTML のように複数のテキスト ブロックがあり、上から下へ流れるようにする場合は、すべての DOM 要素を CSS で絶対位置に配置するのと同じように、手動で配置する必要があります。これを CSS で行うことは想像できるでしょうか?
* { position: absolute; }
これが 3D でのテキスト レイアウトです。詳細ビューでは、title、author、description、duration は、それぞれ独自のスタイル、色、スケールなどを持つ新しい TextBitmap オブジェクトです。
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 で作業する 1 つの機会として、テキストを z 方向に push および pull したり、x、y、z 軸で回転したりできます。
まとめ
WebVR のテキストとレイアウトは、HTML や CSS のように簡単かつ広く利用されるまでには、かなりの時間がかかります。しかし、実際に使えるソリューションは存在し、WebVR では従来の HTML ウェブページよりもはるかに多くのことができます。WebVR は今や存在しています。明日はもっと良いツールが出てくるかもしれません。それまでは、ぜひお試しください。普遍的なフレームワークなしで開発することで、よりユニークなプロジェクトが可能になりますが、これは刺激的です。