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」ボタンの上にあった、格子柄の床がくるくる回るだけの空間です。
テンプレページを確認(スマートフォン&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空間上のカメラの向きを計算すればいいのですが、その計算が結構難しい。
そんなときは!
ドラ○も〜ん!!!
(ちゃらちゃちゃっちゃちゃー)
「でばいすおりえんてーしょんこんとろーるじぇいえすーー!!(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); }
これだけです。
ド○えもんの出番もない!
これで、中身の基本はなんとなくわかったかなと。
次回は、簡単なThree.jsモデルに、この2つを入れてHMDで見てみます!