SONICJAM Developerz Blog

SONICJAM 開発部メンバーによる活動 blog
'); $b.css({"marginLeft":0,"marginRight":0, "marginTop":0, "marginBottom":0, "width":"100%", "paddingBottom":0, "paddingTop":0}); sjdbEffect(["sjdvcnt", "sjdvttl", "sjdvcnv"], 400); }

Oculus Rift と HTML 5

開発部のいなおです。

突然ですが Oculus Rift という名前をご存知の方はどれくらいいるでしょう。これは Oculus VR という新興企業が開発した VR (= virtual reality) つまり「仮想現実」を実現するデバイスの名前です。

Sony の HMZ というヘッドマウントディスプレイならご存知の方もいるでしょう。Oculus Rift はそれとよく似たデバイスです。しかし、より意欲的で、可能性にとんだデバイスといえるでしょう。

その理由は、例えば、3D ゲームの天才プログラマ John Carmack 氏が CTO に迎え入れられたり、つい先日の CEDEC 2013 ではエンジニアリング部門の最優秀賞を受賞したりと、優秀な人材が集い、業界人の期待も非常に高いといった点が示しています。

さらに驚くべきは、これがまだ未発売のデバイスだと言うことです。未発売というのは、机上の空論ということではありません。製品版一歩手前の、開発機のみが現状市場に流通しているという意味です。つまり、まだ始まっていない製品にもかかわらず、その高い可能性を開発機を手にした人達が評価しているということです。

能書きが長くなりました。自分もこの開発機を購入した身なので、今日は Oculus Rift と HTML 5 の連携方法を書いてみようと思います!

vr.js の導入

さて、この開発機 Oculus Rift DK1 (Development Kit 1) は HID デバイスとして認識されます。USB 端子をコンピュータにさせば、ドライバ等のインストールは必要ありません。

Unity などで作成された対応デモは、ケーブルを接続した時点で楽しむことができます。デバイスの導入が非常に簡単なのも魅力の一つでしょう。

ただし、HTML 5 で利用するにはひと手間必要です。ご存知のように web ブラウザから OS のネイティヴ機能にアクセスする標準規格というのは、現状存在しません。なので、Oculus Rift へのアクセスを提供してくれる専用の web ブラウザプラグインを導入します。

vr.js は、WebGL Inspector などで有名な Ben Vanik 氏がオープンソースで公開したプラグインと JavaScript ライブラリの総称です。

vr.js は以下の 2 つの機能を提供します:

  • HID の信号を OS ネイティブ機能から web ブラウザに渡す NPAPI プラグイン
  • NPAPI プラグインの値を JavaScript から参照可能にする JavaScript ライブラリ

NPAPI とは、Mozilla の前身 Netscape が開発したクロスプラットフォームの web ブラウザ用プラグイン規格です。この規格には、Chrome、Firefox、Opera、Safari などの複数 web ブラウザが対応しています。

また、今回はふれませんが、vr.js は Oculus Rift 以外にも、Razor Hydra というゲーム用デバイスにも対応しています (ただしこちらは現状 Windows 環境のみ)。

vr.js の README によると以下の web ブラウザで動作するようです:

  • Chrome 26 以上
  • Firefox 20
  • Safari 6 (Mac OS X)

なので、上記のブラウザが動作する Mac OS X、Linux、もしくは Windows の環境を用意すれば、web ブラウザ上でも Oculus Rift を利用することができます!

vr.js の入手

何はともあれ vr.js を入手しましょう。GitHub 上でソースコードと共に配布されています:

リポジトリの最新スナップショットをアーカイヴでダウンロードしても良いですし、git-clone で取得しても構いません。

NPAPI プラグインの導入

vr.js を入手したら、まずは NPAPI プラグインを導入します。

Mac OS X

  1. リポジトリの bin ディレクトリから npvr.plugin をコピー
  2. ~/Library/Internet Plug-Ins/ 以下にコピーした npvr.plugin を貼り付け

これで Chrome/Firefox/Safari 上で vr.js が使用可能になります。

Windows

Chrome

  1. chrome://extensions を開く
  2. “Developer mode” にチェックし “Load unpacked extension” をクリック
  3. リポジトリの bin フォルダを選ぶ

Firefox

  1. コマンドプロンプトを起動
  2. リポジトリの bin フォルダに cd で移動
  3. install.bat を実行

その他の手順は、リポジトリの README を確認して下さい。

JavaScript ライブラリの使用

つづいて web ブラウザ上から Oculus Rift にアクセスできるか試してみましょう。

リポジトリの lib ディレクトリから vr.js をコピーして、適当な作業ディレクトリに貼り付けます。

あとは、Oculus Rift が接続された状態で、以下のような HTML を用意して、web ブラウザで開いてみましょう。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vr.js</title>
        <script src="vr.js"></script>
        <script>
            (function (w, d, vr) {
                w.addEventListener('load', function () {

                    // NPAPI プラグインの確認
                    if (!vr.isInstalled()) {
                         throw new Error('NPVR plugin not installed.');
                    }

                    // 読込
                    vr.load(function (err) {
                        if (err) throw new Error('NPVR plugin load failed.');

                        // 初期化
                        var vrstate = new vr.State();

                        // センサーの値を取得
                        (function tick () {
                            vr.requestAnimationFrame(tick);

                            if (vr.pollState(vrstate) && vrstate.hmd.present) {

                                // 傾き (クォータニオン) の取得
                                var x = vrstate.hmd.rotation[0],
                                    y = vrstate.hmd.rotation[1],
                                    z = vrstate.hmd.rotation[2],
                                    w = vrstate.hmd.rotation[3];

                                d.body.innerHTML = 'x: ' + x + '<br>' +
                                                   'y: ' + y + '<br>' +
                                                   'z: ' + z + '<br>' +
                                                   'w: ' + w;
                            }
                        })();
                    });

                }, false);
            })(window, document, vr);
        </script>
    </head>
    <body></body>
</html>

HTML に x, y, z, w の値が表示され、Oculus Rift の傾きに応じてこれらの値が変化すれば vr.js の動作確認は完了です。

Three.js による応用

無事に動作が確認できたら、ここからが本番です!

WebGL 界隈では Three.js という JavaScript ライブラリが既に有名です。Oculus Rift を利用するときも、このライブラリを利用することで、難しい処理を省略して、実践的なコードが書き始められます。

魚眼モデルスクリーンのソフウェア処理

Oculus Rift を利用する上でまず必要となるのが、以下の Three.js 拡張ライブラリでしょう:

これは OculusStreetView 用に @troffmo5 が作成した Three.js 用の Effect クラス拡張です。これを利用することで、Oculus Rift がソフウェア処理で実現している次の処理を代行してくれます:

  • 両目用に別々の映像を用意
  • また両目ごとに視差をもたせ立体視を実現
  • レンズの歪みを再現し自然な視野を実現

いわゆる “barrel distortion” と呼ばれる処理を簡単に実現してくれます。

これを利用した立方体を画面中央に表示するコードは以下のようになります:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vr.js</title>
        <script src="three.js"></script>
        <script src="OculusRiftEffect.js"></script>
        <script>
            (function (w, d, THREE) {
                w.addEventListener('load', function () {

                    var WORLD_FACTOR = 1.0;

                    var OculusRift = {
                      hResolution: 1280,
                      vResolution: 800,
                      hScreenSize: 0.14976,
                      vScreenSize: 0.0936,
                      interpupillaryDistance: 0.064,
                      lensSeparationDistance: 0.064,
                      eyeToScreenDistance: 0.041,
                      distortionK: [1.0, 0.22, 0.24, 0.0],
                      chromaAbParameter: [0.996, -0.004, 1.014, 0.0]
                    };

                    var camera, effect, renderer, scene,
                        width = 1280,
                        height = 800,
                        aspect = width / height;

                    renderer = new THREE.WebGLRenderer();
                    renderer.setClearColor(0xffffff);
                    renderer.setSize(width, height);

                    effect = new THREE.OculusRiftEffect(renderer, {
                        HMD: OculusRift, worldFactor: WORLD_FACTOR
                    });

                    camera = new THREE.PerspectiveCamera(90, aspect, 0.1, 1000);
                    camera.position.set(0, 200, 900);

                    scene = new THREE.Scene();

                    var cube, cubeGeometry, cubeMaterial;

                    cubeGeometry = new THREE.CubeGeometry(500, 500, 500, 10, 10, 10);
                    cubeMaterial = new THREE.MeshBasicMaterial({
                        color: 0x00dd00, wireframe: true, transparent: true
                    });
                    cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

                    scene.add(cube);

                    camera.lookAt(cube.position);

                    effect.render(scene, camera);

                    d.body.appendChild(renderer.domElement);

                }, false);
            })(window, document, THREE);
        </script>
    </head>
    <body></body>
</html>

如何でしょう。下図のように表示されたでしょうか。

Cube

表示されれば成功です。コードの要点としては;

  • renderereffect の引数として渡すこと
  • effect.render() にレンダリングを実行させること

でしょうか。

また Oculus Rift DK1 の仕様では;

  • ヘッドマウントディスプレイの解像度は 1280x800
  • 水平視野角は 90 度

ですので、解像度のアスペクト比が 16:10 になるように注意することと、camera の FOV を 90 にすると良いでしょう。

尚、この魚眼モデルスクリーンを自分で実装してみたい人には以下の記事がおすすめです:

センサーの傾き値を反映

次はいよいよ vr.js と Three.js を連携させます。

Oculus Rift で取得できる値は、首の動き、つまり 3 次元の傾きです。これは Three.js の Camera.rotation に該当する値と言えるでしょう。

Three.js ではキーボードやマウスからの入力を Camera の動きや傾きに反映する場合 Controls クラスを用います。Oculus Rift の値を Three.js に反映する例は既にいくつかあるのですが、今回は単純な Controls クラスを自分で実装してみましょう。

前項「JavaScript ライブラリの使用」で紹介した vr.js の動作検証コードと Three.js を組み合わせます:

THREE.OculusRiftControls = function (camera, vrstate) {
    var quaternion = new THREE.Quaternion();

    this.update = function () {
        if (!vr || !vrstate.hmd.present)) return;

        var x = vrstate.hmd.rotation[0],
            y = vrstate.hmd.rotation[1],
            z = vrstate.hmd.rotation[2],
            w = vrstate.hmd.rotation[3];

        quaternion.set(x, y, z, w);

        camera.quaternion = quaternion;
    };
};

これを OculusRiftControls.js といった名前で保存しましょう。

ではこのコードと合わせて、先程の立方体を表示するコードを、Oculus Rift の傾き (頭の動き) によって視点が変わるよう書き換えてみましょう:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vr.js</title>
        <script src="vr.js"></script>
        <script src="three.js"></script>
        <script src="OculusRiftEffect.js"></script>
        <script src="OculusRiftControls.js"></script>
        <script>
            (function (w, d, THREE, vr) {
                w.addEventListener('load', function () {

                    var WORLD_FACTOR = 1.0;

                    var OculusRift = {
                      hResolution: 1280,
                      vResolution: 800,
                      hScreenSize: 0.14976,
                      vScreenSize: 0.0936,
                      interpupillaryDistance: 0.064,
                      lensSeparationDistance: 0.064,
                      eyeToScreenDistance: 0.041,
                      distortionK: [1.0, 0.22, 0.24, 0.0],
                      chromaAbParameter: [0.996, -0.004, 1.014, 0.0]
                    };

                    var vrstate,
                        camera, controls, effect, renderer, scene,
                        width = 1280,
                        height = 800,
                        aspect = width / height;

                    function init () {
                        vrstate = new vr.State();

                        renderer = new THREE.WebGLRenderer();
                        renderer.setClearColor(0xffffff);
                        renderer.setSize(width, height);

                        effect = new THREE.OculusRiftEffect(renderer, {
                            HMD: OculusRift, worldFactor: WORLD_FACTOR
                        });

                        camera = new THREE.PerspectiveCamera(90, aspect, 0.1, 1000);
                        camera.position.set(0, 200, 900);

                        controls = new THREE.OculusRiftControls(camera, vrstate);

                        scene = new THREE.Scene();

                        var cube, cubeGeometry, cubeMaterial;

                        cubeGeometry = new THREE.CubeGeometry(500, 500, 500, 10, 10, 10);
                        cubeMaterial = new THREE.MeshBasicMaterial({
                            color: 0x00dd00, wireframe: true, transparent: true
                        });
                        cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

                        scene.add(cube);

                        camera.lookAt(cube.position);

                        effect.render(scene, camera);

                        d.body.appendChild(renderer.domElement);
                    }

                    function animate () {
                        w.requestAnimationFrame(animate);

                        if (vr.pollState(vrstate)) {
                            effect.render(scene, camera);
                            controls.update();
                        }
                    }

                    if (!vr.isInstalled()) throw new Error('NPVR plugin not installed.');

                    vr.load(function (err) {
                        if (err) throw new Error('NPVR plugin load failed.');
                        init();
                        animate();
                    });

                }, false);
            })(window, document, THREE, vr);
        </script>
    </head>
    <body></body>
</html>

如何でしょう。先程の立方体が頭の動きによって見え方が変わるでしょうか。

今回は傾きを素直に Camera の傾きに反映しましたが、例えば、首を左右に傾かせることで、左右への移動に反映するといったことも考えられます。

ここまでできれば、あとは Three.js を使いこなすことで、色々なことができるでしょう。ぜひおもしろいアイデアを形にしてみて下さい!

まとめ

何を隠そう、自分も Oculus Rift が楽しくて Three.js をさわり始めました。来年はきっと VR の時代になりマス!!! 興味がわいた方は是非今からでも Oculus Rift 開発機を購入してみては如何でしょうか。

公式サイトで販売中です:

また、開発はできないけど、さわってみたい! という方は、有志の方々が開催しているイベントがありますので、足をはこんでみては如何でしょう:

以上デスっ。

comments powered by Disqus