icon-fb icon-tw icon-index_hero icon-cb

three.jsの基本ライブラリのみで超シンプルにwebVRを実装する【最初】

Three.jsでVRなWEBページを作ってみたい!

突然ですが、これから徐々に、VRなWEBの作り方を勉強していこうと思います。
目指すは、カヤックVR部さんや、中ノ瀬翔さんmacros
あと、ジャイロ・加速度センサーの雄、唐揚げキャッチャー。あの精度を取り入れられたぐんと可能性が広がる。

一応、おそらく今VRなWebを作るなら標準となるっぽいライブラリA-FRAMEを使おうと思ってるんですが、その前にちょっと寄り道します。まあのんびりいきます。

※ちなみに、基本的なThree.jsの知識や説明は省くと思います。

Chrome Experiments for Virtual Reality

そんなわけで、目指せA-FRAMEでVRなWEBページ制作ですが、まずはGoogleがChrome×Cardboardの開発用に配信しているテンプレを使ってみます。
おそらくこれが、基本中の基本だと思うので。

テンプレのダウンロードはこちら
→Chrome Experiments for Virtual Reality

ページ中央の「LAUNCH EXPERIMENT」ボタンのリンク先をCardboardでみると、いくつかのサンプルで遊べます。

テンプレはページ下部の「DOWNLOAD CODE」から。

テンプレをダウンロードすると、中にはシンプルなページが入っています。
さっきのページの「DOWNLOAD CODE」ボタンの上にあった、格子柄の床がくるくる回るだけの空間です。


160429_01
テンプレページを確認
(スマートフォン&Cardboardでご確認ください。)

テンプレートの中身

それでは、中身を簡単に見てみましょう。

このテンプレートはThree.jsを基本にしている(というか、Three.jsで作る方法のテンプレ)ので、まずはThree.jsまわりのライブラリを読み込んでいます。

  <script src="js/third-party/threejs/three.js"></script>
  <script src="js/third-party/threejs/StereoEffect.js"></script>
  <script src="js/third-party/threejs/DeviceOrientationControls.js"></script>
  <script src="js/third-party/threejs/OrbitControls.js"></script>

Three.js本体以外に読み込むライブラリは3つ。
StereoEffect.js:HMD用に画面を左右分割する。
DeviceOrientationControls.js:スマートフォンの向きを検知(ジャイロスコープ)。
OrbitControls.js:マウスのドラッグに対応(PC用)。

ちなみにどれもThree.jsのパッケージに入っています。
[/examples/js/effects/StereoEffect.js]
[/examples/js/controls/DeviceOrientationControls.js]
[/examples/js/controls/OrbitControls.js]

このうち、OrbitControlsについては、Three.jsを使ってるとよく出てくるので今回は省きます。

DeviceOrientationControls

スマホ端末の向きは、deviceorientationというイベントで取得することが出来ます。
このイベントからは、“alpha”,”beta”,”gamma”という3軸の回転値を取得でき、

window.addEventListener("deviceorientation", function(event){
    console.log('alpha:', event.alpha);
    console.log('beta:', event.beta);
    console.log('gamma:', event.gamma);
});

このように、端末の向きを数値で取得するというのが基本になります。
この数値から3D空間上のカメラの向きを計算すればいいのですが、その計算が結構難しい。

そんなときは!

nobi-a

ドラ○も〜ん!!!

(ちゃらちゃちゃっちゃちゃー)

dora-a

「でばいすおりえんてーしょんこんとろーるじぇいえすーー!!(DeviceOrientationControls.js!!)」

DeviceOrientationControls.jsは、

var controls = new THREE.DeviceOrientationControls(camera, true);
controls.connect();

と定義して、render()時に

function render() {
  controls.update();
  renderer.render(scene, camera);
}

とすれば、難しい計算をせずに、カメラの向きを変えてくれます。
さすが21世紀!!

参考に、さきほどダウンロードしたテンプレからStereoEffectとOrbitControlsを削除してDeviceOrientationControlsだけにしたものをこちらにアップしました。
スマホで向きが変わることを確認してみてください。
ソースはこちら。

  <script>
    var camera, scene, renderer;
    var effect, controls;
    var element, container;

    var clock = new THREE.Clock();

    init();
    render();

    function init() {
      renderer = new THREE.WebGLRenderer();
      element = renderer.domElement;
      container = document.getElementById('example');
      container.appendChild(element);

      scene = new THREE.Scene();

      camera = new THREE.PerspectiveCamera(90, 1, 0.001, 700);
      camera.position.set(0, 10, 0);
      scene.add(camera);

      controls = new THREE.DeviceOrientationControls(camera, true);
      controls.connect();

      var light = new THREE.HemisphereLight(0x777777, 0x000000, 0.6);
      scene.add(light);

      var texture = THREE.ImageUtils.loadTexture(
        'textures/patterns/checker.png'
      );
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      texture.repeat = new THREE.Vector2(50, 50);
      texture.anisotropy = renderer.getMaxAnisotropy();

      var material = new THREE.MeshPhongMaterial({
        color: 0xffffff,
        specular: 0xffffff,
        shininess: 20,
        shading: THREE.FlatShading,
        map: texture
      });

      var geometry = new THREE.PlaneGeometry(1000, 1000);

      var mesh = new THREE.Mesh(geometry, material);
      mesh.rotation.x = -Math.PI / 2;
      scene.add(mesh);

      window.addEventListener('resize', resize, false);
      setTimeout(resize, 1);
    }

    function resize() {
      var width = container.offsetWidth;
      var height = container.offsetHeight;

      camera.aspect = width / height;
      camera.updateProjectionMatrix();

      renderer.setSize(width, height);
    }

    function render() {
      requestAnimationFrame(render);
      controls.update();
      renderer.render(scene, camera);
    }

  </script>

ちなみに、テンプレではちょっとややこしい実装方法になっていますが、要するに
「とりあえずOrbitControls(マウス操作)でcontrolsを定義しといて、スマホの回転イベント(deviceorientation)が発火したら、controlsをDeviceOrientationControls(ジャイロ)で再定義する」
ということをしてます。(ソース割愛)

StereoEffect

StereoEffectを呼び出すだけで、いつものrendererをVR用の2分割画面でレンダリングすることが出来ます。

rendererを引数として、StereoEffectを定義。

effect = new THREE.StereoEffect(renderer);

リサイズするときはeffectもリサイズ

function resize() {
  var width = container.offsetWidth;
  var height = container.offsetHeight;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  renderer.setSize(width, height);
  effect.setSize(width, height);
}

render()時に、rendererの代わりにeffectを使う。

function render() {
  requestAnimationFrame(render);
  controls.update();
  effect.render(scene, camera);
}

これだけです。

nobi-b

ド○えもんの出番もない!

これで、中身の基本はなんとなくわかったかなと。

次回は、簡単なThree.jsモデルに、この2つを入れてHMDで見てみます!