HTML5Experts.jp

React VRで始めるお手軽WebVRプログラミング

連載: React VR (1)

React VRというのは、Facebookが開発し、GitHubにてBSDライセンスで公開しているオープンソースのVRアプリケーションフレームワークです。現在のところは、Webブラウザ向けにWebGLとWebVRを使ったVRアプリケーションを作るための様々な仕組みを提供しています。

VRコンテンツは、実行して動いた時の満足感がかなり高いです

React VRを知らなくても、ReactやReact Nativeなら知っているという人もいるかもしれません。VRコンテンツを作るには新しいフレームワークやライブラリなどを学ぶ必要がありましたが、Reactと同じ考え方を使ってVRコンテンツを作ることができる点が、他のフレームワークと異なる点です。

ネイティブVRが最高の体験をもたらすとは限らない

VRというと何らかのVRヘッドマウントを装着して体験するものというイメージがあります。また、VRヘッドマウントは高額で、VRを体験するハードルが高かったことも事実です。そんな中、ある程度のクオリティを保ちつつも安価なVRヘッドマウントとして登場したのが、GearVRです。

私もGearVRはすぐに購入してゲームや体験系コンテンツをいろいろと試してみました。もちろん、ジュラシックワールドの恐竜にはリアリティを感じましたし、3Dのシューティングゲームでは3D酔いも体験しました。 しかし、個人的に一番衝撃を受けたのはVR CRUISEの産経フォトです。

当時の産経フォト

特に、「東日本大震災でのタンカーが乗り上げている風景のパノラマ写真」には一番度肝を抜かれました。作りとしては360度写真であり、すごいポリゴン技術を利用しているわけではないのですが、コンテンツが日常生活と地続きにあるという感覚が、リアリティを感じさせ、恐怖を感じさせたのです。

そこで思ったことは、VRといっても受け手の中にある感性によっては、シンプルなコンテンツでも十分に伝わる体験があるということでした。

React VRのアーキテクチャをざっと知る

React VRの公式サイト

React VRを語る上で欠かせないのが、WebVRという仕様と、Three.jsというライブラリの存在です。WebVRは、VRヘッドマウント事態の情報やリアルタイムな傾きや向きなどをWebブラウザへと伝えるための仕様で、これによりGearVRなどでWebVRを閲覧することが出来ます。 Three.jsは、3Dのライブラリです。本誌でも過去に特集されているので改めての説明は省きます。

React VRは、WebVRとThree.jsをJavaScriptでごりごりと作っていくという世界観にもう2レイヤー加えたようなものと言えます。WebVRとThree.jsは、OVRUIというレイヤーでラッピングされ、そのAPIをReactコンポーネントを通じてユーザーは利用するということになります。

早速作ってみよう

では早速、React VRでまずはプログラムを作ってみましょう。React VRに付属している「Hello World」サンプルで、一通りの最低限な使い方を学んでみることにします。

React VRはReactとついているので、ちょっと怖気づいてしまうかもしれませんが、サンプル自体は非常に簡単です。まず初めに言っておきますと、React VRではターミナル(コマンドプロンプト)を頻繁に使います。なので、MacOSであれば「ターミナル」、Windowsであれば「コマンド プロンプト」を使ってサンプル作成を進めることになります(以降はWindows環境を前提として進めますが、Macでも同様に試して頂けます)。

React VRのコンソールツールをインストール

React VRには、react-vr-cliというコンソールツールが用意されており、インストールするとreact-vrというコマンドが使えるようになります。ということで、なにはともあれこのツールをインストールしましょう。react-vr-cliは、Node.js製のツールなのでまだな方は「Node.js」を導入しておきましょう。

続いてreact-vr-cliを、Node.jsのパッケージマネージャーであるnpmコマンドでインストールしていきます。

$ npm install -g react-vr-cli

... 略 ...

C:\Program Files (x86)\Nodist\bin\react-vr -> C:\Program Files (x86)\Nodist\bin\node_modules\react-vr-cli\index.js C:\Program Files (x86)\Nodist\bin `-- react-vr-cli@0.3.2

最後のメッセージから、react-vr-cliのバージョン0.3.2がインストールされたことが確認できます。

まず試しにreact-vrコマンドを実行してみましょう。

$ react-vr

React VR Command Line Interface Version 0.3.2

Usage: react-vr init [project name] Create a new React VR application with the specified name

コマンドの出力結果から、react-vr コマンドには init というサブコマンドが一つだけ用意されていることがわかります。コマンドにプロジェクト名を渡すと、新規React VRプロジェクトが作成されるようです。今回は「Hello World」を表示させるので、HelloWorldというプロジェクト名にします。

$ react-vr init HelloWorld

Enterキーを押すとなにやらいろいろとプログラムが走り出して、ごにょごにょと長いメッセージが表示されたあと、プロンプトへ戻ります。これで、HelloWorldプロジェクトが作成されました。

続いて、「HelloWorld」ディレクトリに入り、早速何も変更しないまま実行してみましょう。npm startというコマンドを使います。

$ cd HelloWorld
$ npm start

すると、またごちゃっとメッセージがコマンドラインに表示されて、Loading dependency graph, done.というメッセージが最後に表示されます。

$ npm start

> HelloWorld@0.0.1 start C:****\HelloWorld > node -e "console.log('open browser at http://localhost:8081/vr/\n\n');" && node node_modules/react-native/local-cli/cli.js start

open browser at http://localhost:8081/vr/

... 略 ...

Loading dependency graph, done.

この表示が出たら、ブラウザでhttp://localhost:8081/vr/を開いてみましょう。

helloと表示された。一安心。

「hello」と表示されているのがわかると思います。マウスで画面をドラッグしてみましょう。

ちゃんとHello World!にする

さて、「hello」と表示されているのは確認できましたので、今度はプログラムを修正して、ちゃんと「Hello World!」と出力されるようにしてみましょう。プロジェクトフォルダ内にある「index.vr.js」を開いてください。

エディタは各自使い慣れたもので構いません。ただしReact VRの新規プロジェクト作成で行った場合、ECMAScript 2015(ES6)形式でコードが生成されます 。また、JSX (React専用の特殊な記法) も使用するので、これらのスタイルに対応しているエディタを使用しましょう。Visual Studio Codeであれば、標準でJSXに対応しているのでおすすめです。

エディタで「index.vr.js」を開くと、こんな箇所があるはずです。ここで、先ほど表示していた3D空間の全要素を定義しています。

export default class HelloWorld extends React.Component {
  render() {
    return (
      <View>
        <Pano source={asset('chess-world.jpg')}/>
        <Text
          style={{
            backgroundColor: '#777879',
            fontSize: 0.8,
            fontWeight: '400',
            layoutOrigin: [0.5, 0.5],
            paddingLeft: 0.2,
            paddingRight: 0.2,
            textAlign: 'center',
            textAlignVertical: 'center',
            transform: [{translate: [0, 0, -3]}],
          }}>
          hello
        </Text>
      </View>
    );
  }
};

ここでは通常のReactコンポーネントと同様、React.Componentを継承したクラスを定義し、renderメソッドをオーバーライドしています。React VRは、通常のReactとほぼ同じスタイルでVRコンテンツを表示できるということです。

ポイントは、render()メソッド内で使用しているコンポーネントです。ここで使用されているViewコンポーネントやPanoコンポーネント、Textコンポーネントなどは、React VRの独自コンポーネントなので、使い方を把握する必要があります。

Viewコンポーネントというのは、HTMLでいうところのdivだと思ってください。何かのまとまりとして、様々な3D要素を内包出来ますし、Viewコンポーネント自体にスタイルを適用することもできます。このスタイルは、Reactを使ったことがある方であれば馴染みのある定義方法だということがわかるでしょう。プロパティはCSSと違い、キャメルケースで記述していきます。ほとんどスタイルシートのような感覚で、3Dオブジェクトのスタイルを定義することができる のは感動ものです。

Panoコンポーネントは、パノラマ写真を埋め込んだ空間を簡単に作成できるコンポーネントです。次回の記事では実際にPanoコンポーネントを使ってVRコンテンツを作ります。

「hello」という文字列が表示されるように定義してあるのはTextコンポーネントです。Textコンポーネントは、文字通りテキストを表示するためのコンポーネントで、スタイルの定義と内容が記述されています。スタイルは見たことがないlayoutOriginというプロパティなどはありますが、他はほぼCSSのままであることが確認できると思います。

では、「hello」を「Hello World!」へ書き換えていきましょう。書き換えたTextコンポーネント部分はこんな感じになります。

<Text
  style={{
    backgroundColor: '#777879',
    fontSize: 0.8,
    fontWeight: '400',
    layoutOrigin: [0.5, 0.5],
    paddingLeft: 0.2,
    paddingRight: 0.2,
    textAlign: 'center',
    textAlignVertical: 'center',
    transform: [{translate: [0, 0, -3]}],
  }}>
  Hello World!
</Text>

さて、ブラウザをリロードしてみましょう。無事「Hello World!」と表示されたことと思います。

Hello World!と表示された

日本語を表示させたら、***になった!

ただ、実はReact VRは現在のバージョンでは、そのままでは日本語の表示ができません。試しに「Hello, World!」の代わりに日本語を入れて試してみると、以下のように文字列が「***」と表示されてしまいます。

日本語を表示しようとしたら***になるの巻

詳しくはReact VRのドキュメント「Fonts and Text」に書かれていますが、大きく分けて2つのステップで日本語表示が実現できます。

1. まずは日本語フォントをダウンロード

React VRのGitHubへ行き、OVRUI/fonts以下にある「japanese.fnt」「japanese.png」をダウンロードします。

ダウンロードしたフォント定義ファイルおよびフォントセットテクスチャは、「static_assets/fonts」以下に配置します。「fonts」ディレクトリは自身で作成してください。 ちなみに、「japanese.fnt」「japanese.png」は、独自のものを作ることもできますし、React VRに用意されているこちらの「react-vr/tools/fontue at master · facebook/react-vr」ツールを使って作ることも出来ます。オリジナルのフォントセットテクスチャを作成する場合はフォントのライセンスをご確認の上利用しましょう。

2. 日本語フォントを読み込むように「vr/client.js」を修正

日本語フォントを使うようにするには、「vr/client.js」を修正します。8行目以下に下記のような行があることと思います。

function init(bundle, parent, options) {
  const vr = new VRInstance(bundle, 'HelloWorld', parent, {
    // Add custom options here
    ...options,
  });
  vr.render = function() {
    // Any custom behavior you want to perform on each frame goes here
  };
  // Begin the animation loop
  vr.start();
  return vr;
}

ここを修正していきます。ポイントは下記3点です。

  1. OVRUIライブラリをインポートする
  2. OVRUI.loadFontメソッドで読み込むフォントセットと読み込み後の処理を記述する
  3. React VR Webの新しいインスタンスを作成するときのオプションに読み込んだフォントを指定する

OVRUIというのは、WebVRのためのフレームワークで、Three.jsのシーン(様々な3Dオブジェクトを置く場所)をラップしてVRヘッドマウントを含むデバイスからアクセスできるようにしたり、3Dのビューをテキストつきでレンダリングしたりといった機能を含んでいます。

このうち、テキストのレンダリングについては、Signed-Distance Functionという仕組みを使ってなめらかなフォントレンダリングを行う仕組みが用意されています。この仕組みのおかげで、フォントを導入するのが面倒な感じになっているのですが、フォントのレンダリング面では、3Dに表示するものとしてはゆがみが少なく、読みやすいものになっているのではと思います。

ということでやるべきこととしては、この仕組みに対応したフォント関係のファイルを用意し、VRコンテンツの開始前にフォント定義ファイルおよびフォントセットテクスチャを読み込み、その後コンテンツが始まるように書くことで、日本語に対応した表示を実現することができるのです。

OVRUI.loadFontメソッドの返り値は、Promiseです。なので、thenメソッドを使うことで、読み込み後の処理の中でvrインスタンスを返す処理を書けばいいということになります。Promiseについては、過去の高津戸さんの記事「Promiseで簡単!JavaScript非同期処理入門【前編】」が詳しいです。

また、OVRUI.loadFontメソッドの実行結果は、fontという値で取得するように書いているので、これを初期化オプションにfontというキーに含めて渡してあげます。

以上の処理を書き加えたものが以下となります。

import * as OVRUI from 'ovrui'; // ← 追加

function init(bundle, parent, options) { OVRUI.loadFont( '/static_assets/fonts/japanese.fnt', '/static_assets/fonts/japanese.png' ).then((font) => { const vr = new VRInstance(bundle, 'HelloWorld', parent, { // Pass in the custom font as an initialization property font: font, // ← 追加 ...options, }); vr.render = function() { // Any custom behavior you want to perform on each frame goes here }; // Begin the animation loop vr.start(); return vr; }); }

意外に大変でしたが、これで日本語の表示ができるようになったはずです。「Hello World!」のところを日本語にし、コンソールで一旦コンソールを再起動したあと、ブラウザをリロードしてみてください。

無事日本語を表示できるようになった

今回は「Hello, World」と日本語コンテンツの表示を行いました。次回はいよいよ、360度画像を用いたパノラマ表示にチャレンジしていきます。