※ 『Hokuriku.NET Vol.13 in 富山「3D で遊ぼう ~C#er も TypeScript で楽々 WebGL~」』の資料の内容の解説。
今回は、TypeScript を使って WebGL に挑戦してみよう。
素で使うと中々に取っつき難い WebGL だが、TypeScript を使うことで比較的楽に使うことができる。 C#er の方も是非 Web での 3D プログラミングに興味を持っていただきたい。
WebGL とは
WebGL は、HTML5 の Canvas に三次元 (または二次元) のグラフィックを表示する標準仕様だ。
Web ブラウザーで、プラグインなしで動作する。
WebGL 動作環境
現状 WebGL は、PC 上のブラウザーでは、最新の IE、Google Chrome、FireFoxでは、ほぼ動作する。但し全てが動くとは限らない。
モバイルで動作するものは多くない。
モバイル環境の WebGL 対応状況
Platform | iPhone, iPad | Phones & Tablet | Android 4.0+ | Kindle Fire | Phones | BB10 | Tablet | MeeGo - N9 | Symbian | Windows Phone | Windows 8 | Android & Symbian | Java,iOS Android | Android, MeeGo* | Firefox OS |
WebGL 3D Canvas for the web |
○ Specific device |
○ 30+ |
○ |
○ 2.0+ |
○ 11+ |
○ 12+ (android) |
○ |
○ |
Windows RT タブレットでは動作する。
WebGL プログラミング
WebGL のプログラミングには、シェーディング言語である GLSL (OpenGL 2.0) と JavaScript を用いる。
次の図のような感じだ。左側が GLSL、右側が JavaScript による部分だ。
慣れていない人には、結構大変だ。
three.js
そこで、ここでは three.js という JavaScript のライブラリを用いることによる。
three.js は、WebGL のラッパーで、WebGL を抽象化して易しく使えるようにしてくれるのだ。
次の場所で入手することができる。
ダウンロードし、three.js または three.min.js というファイルを HTML ファイルから参照すれば OK だ。
three.d.ts
three.js を TypeScript から使う為には、型定義ファイルの three.d.ts も必要だ。
こちらは、次の場所で入手することができる。
または、NuGet で入手することができる。
Visual Studio で NuGet を検索してインストールすることも可能だ。
この three.d.ts を自分の TypeScript ファイルから参照する。
three.js による 3D プログラミング
では three.js で 3D プログラミングを始めてみよう。
ここでは、次のような順序で進めていく。
- 0. 準備
- 1. WebGL レンダラーの作成
- 2. カメラの作成
- 3. シーン (空間) の作成
- 3.1 ライト (光源) の作成 → シーンに追加
- 3.2 メッシュの作成 ― ジオメトリー (形) とマテリアル (材料) からメッシュを作成 → シーンに追加
- 4. レンダリング ― レンダラーとカメラでシーンをレンダリング
0. 準備
- 0.1 『[TypeScript] TypeScript の特長』を参考に、Visual Studio で「TypeScript を使用した HTML アプリケーション」を作成する。
- 0.2 three.min.js と three.d.ts をプロジェクトのフォルダーに置く (ここではプロジェクトのフォルダーにその儘フラットに置いている)。
- 0.3 threejswebglsample.ts というファイル名の TypeScript ファイルをプロジェクトに追加する。
- 0.4 threejswebglsample.ts の一行目に、
/// <reference path="three.d.ts"/>
という1行を書き、three.d.ts を参照する
(three.d.ts が threejswebglsample.ts と異なるフォルダーにある場合は、相対パスで書く)。 - 0.5 threejswebglsample.html というファイル名の HTML ファイルをプロジェクトに追加する。
threejswebglsample.html では、three.min.js と threejswebglsample.ts から生成される threejswebglsample.js を参照する。
次のようにする。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <script src="three.min.js"></script> <script src="threejswebglsample.js"></script> <title>THREE.js で WebGL</title> </head> <body> <div id="viewport"></div> </body> </html>
中に viewport という id の div があるが、後で three.js によって、この中に Canvas を作る。
1. WebGL レンダラーの作成
レンダラーを作成する TypeScript のコードは次のようになる。
// 1. WebGL レンダラーを作成 try { var renderer = new THREE.WebGLRenderer({ antialias: true }); } catch (e) {} if (renderer == null) { alert("お使いの環境では WebGL はご利用いただけません。"); return; } // サイズの設定 renderer.setSize(window.innerWidth, window.innerHeight); // 背景色の設定(色, 透明度) renderer.setClearColorHex(0x000000, 1); // レンダラーによって、viewport の ID を持つ HTML 要素に子要素として canvas を追加 document.querySelector("#viewport").appendChild(renderer.domElement);
これで描画する準備ができた。
2. カメラの作成
次にカメラを作成する。
// 2. カメラを作成 // (透視投影の) カメラを作成 var fov = 100; // 画角 var aspect = window.innerWidth / window.innerHeight; // 縦横比 var camera = new THREE.PerspectiveCamera(fov, aspect); camera.position = new THREE.Vector3(0, 0, 1000); // z 方向に 1000 ずらす
カメラは、z 方向に 1000 ずらした位置に置くことにする。
3. シーン (空間) の作成
シーン (空間) を作成する。 シーンには、後でライト (光源) を置いたり、メッシュと呼ばれるオブジェクトを配置したりする。
// 3. シーン (空間) を作成 var scene = new THREE.Scene();
シーン (空間) が作成された。
3.1 ライト (光源) の作成 → シーンに追加
ライト (光源) を作成し、シーンに追加する。
ライトには幾つかの種類があるが、ここでは太陽光のような平行光源 (無限遠光源) を作成する。
// 3.1 ライト (光源) を作成 → シーンに追加 // 平行光源 (無限遠光源) を作成 var directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 引数: 色, 強さ directionalLight.position = new THREE.Vector3(0, 0, 1); // z 方向から照らす // 光源をシーンに追加 scene.add(directionalLight);
シーン (空間) にライト (光源) が置かれた。
3.2 メッシュの作成 ― ジオメトリー (形) とマテリアル (材料) からメッシュを作成 → シーンに追加
ジオメトリー (形) とマテリアル (材料) からメッシュを作成し、シーンに追加する。
three.js では、予めプリミティブ (基本的な) ジオメトリー (形) が幾つか用意されている。ここでは、その中から直方体を作成する。
また、マテリアル (材料) も幾つもの種類が用意されているが、ここでは単純な色だけを持ったものを用いる。
// 3.2 メッシュを用意 → シーンに追加 // ジオメトリー (形) とマテリアル (材料) からメッシュを作成 // プリミティブなジオメトリーを作成 var geometry = new THREE.CubeGeometry(500, 500, 500); // マテリアルを作成 (赤) var material = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // ジオメトリーとマテリアルを合わせてメッシュを作成 var cubeMesh = new THREE.Mesh(geometry, material); // メッシュをシーンに追加 scene.add(cubeMesh);
これで、シーン (空間) にメッシュが置かれた。
4. レンダリング ― レンダラーとカメラでシーンをレンダリング
最後にレンダリングを行うと描画される。
// 4. レンダリング - レンダラーとカメラでシーンをレンダリング renderer.render(scene, camera);
ここまでをクラスのメソッドに入れ、実行できるようにしてみよう。threejswebglsample.ts は、こうなる。
/// <reference path="three.d.ts"/> module ThreeJSWebGLSample { export class Application { static run() { // 1. WebGL レンダラーを作成 try { var renderer = new THREE.WebGLRenderer({ antialias: true }); } catch (e) {} if (renderer == null) { alert("お使いの環境では WebGL はご利用いただけません。"); return; } // サイズの設定 renderer.setSize(window.innerWidth, window.innerHeight); // 背景色の設定(色, 透明度) renderer.setClearColorHex(0x000000, 1); // レンダラーによって、viewport の ID を持つ HTML 要素に子要素として canvas を追加 document.querySelector("#viewport").appendChild(renderer.domElement); // 2. カメラを作成 // (透視投影の) カメラを作成 var fov = 100; // 画角 var aspect = window.innerWidth / window.innerHeight; // 縦横比 var camera = new THREE.PerspectiveCamera(fov, aspect); camera.position = new THREE.Vector3(0, 0, 1000); // z 方向に 1000 ずらす // 3. シーン (空間) を作成 var scene = new THREE.Scene(); // 3.1 ライト (光源) を作成 → シーンに追加 // 平行光源 (無限遠光源) を作成 var directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 引数: 色, 強さ directionalLight.position = new THREE.Vector3(0, 0, 1); // z 方向から照らす // 光源をシーンに追加 scene.add(directionalLight); // 3.2 メッシュを用意 → シーンに追加 // ジオメトリー (形) とマテリアル (材料) からメッシュを作成 // プリミティブなジオメトリーを作成 var geometry = new THREE.CubeGeometry(500, 500, 500); // マテリアルを作成 (赤) var material = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // ジオメトリーとマテリアルを合わせてメッシュを作成 var cubeMesh = new THREE.Mesh(geometry, material); // メッシュをシーンに追加 scene.add(cubeMesh); // 4. レンダリング - レンダラーとカメラでシーンをレンダリング renderer.render(scene, camera); } } } // ウィンドウがロードされた時 window.onload = () => { // アプリケーションの起動 ThreeJSWebGLSample.Application.run(); };
実行 その 1
コンパイルして threejswebglsample.js を生成し、threejswebglsample.html を Internet Explorer 11 以降等の WebGL 対応の Web ブラウザーで表示してみよう。
赤い四角形が表示された。
実際には、立方体なのだが、真横から見ている為単なる正方形に見える。
実行 その 2
これでは面白くないので、アニメーションをさせてみよう。
アニメーションをさせる為に次のようなコードでレンダリングしてみる。 メッシュの角度を少しずつ変化させるコードを requestAnimationFrame で再帰的に呼び出す。
これで立方体が少しずつ回転する。
static rendering(renderer: THREE.Renderer, camera: THREE.Camera, scene: THREE.Scene, cubeMesh: THREE.Mesh) { // メッシュを自転 cubeMesh.rotation.x += 0.01; cubeMesh.rotation.y += 0.01; // レンダリング renderer.render(scene, camera); // 繰り返す // - setInterval(render, 1000 / 60); より軽い // -- 不要な場合にループを行わない // -- 最適化されている requestAnimationFrame(() => Application.rendering(renderer, camera, scene, cubeMesh)); }
このコードを追加すると、threejswebglsample.ts 全体は次のようになる。
/// <reference path="three.d.ts"/> module ThreeJSWebGLSample { export class Application { static run() { // 1. WebGL レンダラーを作成 try { var renderer = new THREE.WebGLRenderer({ antialias: true }); } catch (e) {} if (renderer == null) { alert("お使いの環境では WebGL はご利用いただけません。"); return; } // サイズの設定 renderer.setSize(window.innerWidth, window.innerHeight); // 背景色の設定(色, 透明度) renderer.setClearColorHex(0x000000, 1); // レンダラーによって、viewport の ID を持つ HTML 要素に子要素として canvas を追加 document.querySelector("#viewport").appendChild(renderer.domElement); // 2. カメラを作成 // (透視投影の) カメラを作成 var fov = 100; // 画角 var aspect = window.innerWidth / window.innerHeight; // 縦横比 var camera = new THREE.PerspectiveCamera(fov, aspect); camera.position = new THREE.Vector3(0, 0, 1000); // z 方向に 1000 ずらす // 3. シーン (空間) を作成 var scene = new THREE.Scene(); // 3.1 ライト (光源) を作成 → シーンに追加 // 平行光源 (無限遠光源) を作成 var directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 引数: 色, 強さ directionalLight.position = new THREE.Vector3(0, 0, 1); // z 方向から照らす // 光源をシーンに追加 scene.add(directionalLight); // 3.2 メッシュを用意 → シーンに追加 // ジオメトリー (形) とマテリアル (材料) からメッシュを作成 // プリミティブなジオメトリーを作成 var geometry = new THREE.CubeGeometry(500, 500, 500); // マテリアルを作成 (赤) var material = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // ジオメトリーとマテリアルを合わせてメッシュを作成 var cubeMesh = new THREE.Mesh(geometry, material); // メッシュをシーンに追加 scene.add(cubeMesh); // 4. レンダリング - レンダラーとカメラでシーンをレンダリング Application.rendering(renderer, camera, scene, cubeMesh); } static rendering(renderer: THREE.Renderer, camera: THREE.Camera, scene: THREE.Scene, cubeMesh: THREE.Mesh) { // メッシュを自転 cubeMesh.rotation.x += 0.01; cubeMesh.rotation.y += 0.01; // レンダリング renderer.render(scene, camera); // 繰り返す // - setInterval(render, 1000 / 60); より軽い // -- 不要な場合にループを行わない // -- 最適化されている requestAnimationFrame(() => Application.rendering(renderer, camera, scene, cubeMesh)); } } } // ウィンドウがロードされた時 window.onload = () => { // アプリケーションの起動 ThreeJSWebGLSample.Application.run(); };
コンパイルして表示してみよう。
今度は、立方体が回っているのが分かるだろう。
実行 その 3
試しに、マテリアル (材料) を換えてみよう。 例えば、
// マテリアルを作成 (赤) var material = new THREE.MeshLambertMaterial({ color: 0xff0000 });
の部分を、
// マテリアルを作成 (赤) var material = new THREE.MeshPhongMaterial({ color : 0xff0000, specular : 0xcccccc, shininess: 50 , ambient : 0xffffff });
に変えてコンパイルし、表示してみよう。
先程のものより艶のある立方体が表示された筈だ。
実際のサンプルを次の場所に用意した。
マテリアル (材料) を変えたり、ジオメトリー (形) を立方体以外にしたり、ライト (証明) を変えたり、アニメーションを変えたり、色々と試してみてほしい。 3D のものが表示されるのは楽しいものだ。
次回は、別のサンプルをご紹介する。