※ 『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 のものが表示されるのは楽しいものだ。
次回は、別のサンプルをご紹介する。