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で見てみます!