【WebGL】Three.jsを使ったWebGLに再挑戦
3年ほど前にWebGLのJSらいぶらりー「Three.js」を使ってみたという記事を書いたのですが、
その頃はWebGLの利用できる環境が限られていたことと(iPhoneでは利用できなかったり、PCでもブラウザの設定が必要な場合などがあった)、
Three.jsを利用するとWebGLが利用しやすくなるとはいえ、3Dをプログラムで扱う難易度の高さに変わりはないということがあり、
一旦リタイアしていました。
しかし2016年の今、WebGLが利用できる環境は一般的となってきていて、
Unityなど、WebGLを出力できる開発環境も増えてきているなどの理由から、
WebGLを利用したサイトが現実味を帯びてきています。
WebGLが持っている可能性はとても大きく、
扱う手段を習得することは、Webデザインの可能性を大きく広げることになります。
そこで、以前リタイアしていたWebGLに、Three.jsを利用して再挑戦していくことにしました。
今回は、軸、立方体、ライトという基本的な図形を表示し、
ドラッグによってカメラの位置を移動するという基本的なものに挑戦してみました。
↓こちらが作ってみたもの
DEMO
See the Pen Three.jsによるWebGLに再挑戦1 by Tomoya Ninomiya (@TomoyaNinomiya) on CodePen.
↓基本的な流れはこちらの本を参考にさせていただいています。
three.jsによるHTML5 3Dグラフィックス〈上〉―ブラウザで実現するOpenGL(WebGL)の世界 2013/09 遠藤 理平著
方法
- Three.jsをダウンロードして設置
- Canvasを設置するHTMLを準備
- Three.jsのコードを記述
- Three.jsの初期設定
- カメラの設置
- オブジェクトの設置
- 描画の実行
- jQueryを使って、ドラッグの処理とカメラの移動を実装
1. Three.jsをダウンロードして設置
Three.jsを公式サイトからダウンロードして下さい。
左上のdownloadというところからダウンロードできます。
ダウンロードすると、320MBほどのファイルがダウンロードされるのでびっくりしてしまいますが、
実際に使うのはその中のthree.min.jsという500KBほどのファイルだけになります。
buildというフォルダの中に入っています。
1 | <script src="js/three.min.js"></script> |
2. Canvasを設置するHTMLを準備
Three.jsを使う場合、基本的にCanvas要素は指定した要素の子要素として、
Three.jsを通して設置することになります。
そのため、HTML上では、Canvasを設置する親要素を設置しておけばOKです。
1 | <div id="canvas-frame"></div> |
3. Three.jsのコードを記述する
いよいよ、Three.jsを使ってWebGLを操作していきます。
1. Three.jsの初期設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | window.addEventListener("load", function() { threeStart(); }); function threeStart() { initThree(); //Three.jsを初期化 initCamera(); //カメラを初期化 initObject(); //オブジェクトを初期化 draw(); //描画実行 } //各共通オブジェクトを格納する変数を初期化 var renderer, //レンダラーオブジェクト scene, //シーンオブジェクト camera, //カメラオブジェクト canvasFrame; //canvasの枠となるDOM要素 /* Three.jsの初期設定 */ function initThree() { canvasFrame = document.getElementById("canvas-frame"); //WebGLのCanvasを設置する親要素を取得 //レンダラーを設定 renderer = new THREE.WebGLRenderer({ antialias: true //アンチエイリアスをONに }); renderer.setSize(canvasFrame.clientWidth, canvasFrame.clientHeight); //親要素の大きさからレンダラーのサイズを設定 canvasFrame.appendChild(renderer.domElement); //Canvasを親要素に設置 renderer.setClearColor(0x000000, 0); //背景色を設定 scene = new THREE.Scene(); //シーンを設定 } |
主要な操作はそれぞれ関数にまとめておくと、後々扱いやすくなります。
ここでの主な操作は、THREE.WebGLRendererの呼び出し、設定と、
THREE.Sceneの呼び出し、設定です。
基本的に、ここで設定した場所へ、カメラを配置したり、オブジェクトを配置したりします。
2. カメラの設置
1 2 3 4 5 6 7 8 | /* カメラを設定 */ function initCamera() { camera = new THREE.PerspectiveCamera(45, canvasFrame.clientWidth / canvasFrame.clientHeight, 1, 10000); /* パースのついたカメラを設定。視野角, アスペクト比, カメラから視体積の手前までの距離、カメラから視体積の奥までの距離を指定 */ camera.position.set(80, 80, 80); //カメラの位置をx, y ,zで指定 camera.up.set(0, 0, 1); //カメラの上の方向 camera.lookAt({ x: 0, y: 0, z: 0 }); //カメラの視野中心座標 } |
場所が準備出来たら、カメラを設置します。
今回は通常使うことの多いパース(遠近)のついたカメラを設置しています。
3. オブジェクトの設置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | var axis, //軸オブジェクトの初期化 box, //立方体オブジェクトの初期化 light; //ライトオブジェクトの初期化 function initObject() { //軸 axis = new THREE.AxisHelper(50); //軸オブジェクトの呼び出し scene.add(axis); //シーンに追加 axis.position.set(0, 0, 0); //位置を設定 //立方体 var geometry = new THREE.BoxGeometry( 30, 30, 30 ), //BOXオブジェクトの呼び出し material = new THREE.MeshPhongMaterial( { //質感の設定 color: 0x156289, //色 emissive: 0x072534, //発光色 shading: THREE.FlatShading //フラットシェーディングを適用 }), cube = new THREE.Mesh( geometry, material ); //Meshを設定 scene.add( cube ); //シーンに追加 cube.position.set(15, 15, 15); //位置を設定 //ライト var light = new THREE.PointLight( 0xffffff, 1, 0 ); //点ライトオブジェクトの呼び出し scene.add( light ); //シーンに追加 light.position.set( 0, 100, 200 ); //位置を設定 } |
いよいよ映し出すオブジェクトを設置していきます。
基本的な流れとしては、
今回の場合はThree.jsで予め用意してある形状を利用しますので、
- Three.jsの中から必要なオブジェクトを呼び出し
- オブジェクトの特性を設定
- シーンに追加
- 位置を設定
という流れになります。3と4は入れ替わっても問題ありません。
4. 描画の実行
1 2 3 4 | function draw() { renderer.clear(); //レンダラーの描画をクリア renderer.render(scene, camera); //レンダリング } |
描画はレンダラーのクリアと、レンダリングの2つを行います。
レンダリングのときに、設定したシーンオブジェクトとカメラオブジェクトを指定します。
これで描画は完了です。
4. jQueryを使って、ドラッグの処理とカメラの移動を実装
せっかくなので、今回はドラッグに合わせてカメラが移動する操作を実装してみます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /*-- 操作 --*/ //イベントの振り分け var EVENT = {}; if ('ontouchstart' in window) { EVENT.TOUCH_START = 'touchstart'; EVENT.TOUCH_MOVE = 'touchmove'; EVENT.TOUCH_END = 'touchend'; } else { EVENT.TOUCH_START = 'mousedown'; EVENT.TOUCH_MOVE = 'mousemove'; EVENT.TOUCH_END = 'mouseup'; } $(function() { var $contentFlickData = {}; $("#canvas-frame").on(EVENT.TOUCH_START, function(e) { //ドラッグ開始 $contentFlickData = { "pageY": e.originalEvent.pageY ? e.originalEvent.pageY : e.originalEvent.changedTouches[0].pageY, "startTime": date.getTime() } }).on(EVENT.TOUCH_MOVE, function(e) { //ドラッグ中 e.preventDefault ? e.preventDefault() : e.returnValue = false; var pageY = e.originalEvent.pageY ? e.originalEvent.pageY : e.originalEvent.changedTouches[0].pageY; //camera.position.set(80, 80 + , 80); //draw(); if($contentFlickData.pageY) { camera.position.set(80 + Math.floor(($contentFlickData.pageY - pageY) / 2), 80 + Math.floor(($contentFlickData.pageY - pageY) / 2) , 80); //カメラをドラッグに合わせて移動 draw(); } }).on(EVENT.TOUCH_END, function(e) { var pageY = e.originalEvent.pageY ? e.originalEvent.pageY : e.originalEvent.changedTouches[0].pageY; camera.position.set(80, 80, 80); //カメラを元の位置に戻す $contentFlickData = {}; }); }); |
マウスとタッチの振り分けを行い、レスポンシブに配慮します。
pageYでドラッグの縦座標を取得し、その移動量に合わせてカメラを移動します。
先は長いですが、なんとか自由に扱えるようになりたいです。
Author Profile
NINOMIYA
Webデザイナー兼コーダー出身のフロントエンド開発者です。 UXデザインやチーム開発の効率化など、勉強中です。
SHARE