Advanced Tech Night No.7
3DCG (3Dコンピュータグラフィック)を
WebGLで始めよう!
2013/08/30
Acroquest Technology 株式会社
秋葉 誠
自己紹介
 秋葉 誠 (@mac_akiba)
 公共向け集中監視システム
フレームワーク開発やってました
 バックエンド系中心
現在はインフラ系のお仕事
・Linux
・PostgreSQL
・Hadoop
など
Advanced Tech Night
1
久しぶりに、
フロントエンド系の
技術を触ってみました。
発表内容!
1. WebGLとは?
2. WebGLを使ってみよう
3. WebGLを使う場合の注意点
4. ライブラリの紹介
5. まとめ
Advanced Tech Night
2
1.WebGLとは?
Advanced Tech Night No.7
3DCGをWebGLで始めよう!
Advanced Tech Night
3
1-1.WebGLとは?
1. WebGLはWeb( JavaScript )用
のOpenGL ES 2.0(※)ライブラリ
(※)OpenGL ES: OpenGLの組み込み版
① JavaScriptからOpenGL ES 2.0を呼び出すブリッジAPI
→対応ブラウザならば、プラグイン無しに、ブラウザ上で高速に
3D表示ができる。
② グラフィックスカードがOpenGLに対応している必要あり。
2. WebGLが生まれた経緯
① 最初は、MozillaがCanvas3Dの実験を開始。
② 2009年に、Khronos(クロノス)グループがWebGLワーキンググループ
を発足。
③ 2011年に、WebGL1.0が仕様化。
④ 2013/08現在、Version1.0.2が最新。
Advanced Tech Night
4
1-2.WebGLは高速/高機能だが実装が大変
Advanced Tech Night
5
1. OpenGL ES2をJavaScriptに落とし込んでいる
→同じ機能が使える(=高機能)、GPUを使った高速描画
WebGL Canvas SVG Flash
高速描画
◎ △
ライブラリ/
オブジェクト数による
× ○
3D描画機能
◎ △ △ ○
実装の簡単さ × × △ ○
オーサリングツールが
必要
DOMイベント × ○ △ ○
DOMではないが
イベントの作成に対応
文字列描画 × △
埋込みフォント未対応
○ ○
互換性 ×
今後増えるかも?
△
IE以外はだいたいOK
○ △
モバイルでは動かない
けど、安くない... (実装が面倒)
美味い! (OpenGL ES2の機能そのまま)
速い! (GPUで高速描画)
1-2.WebGLは高速/高機能だが実装が大変
2. WebGLだけだと、どんだけ大変?
 簡単な三角形(平面)を書くなんだけど…
Advanced Tech Night
6
onload = function() {
// canvasエレメントを取得
var c = document.getElementById('canvas');
c.width = 500;
c.height = 500;
var gl = c.getContext('webgl') ||
c.getContext('experimental-webgl');
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// 頂点シェーダとフラグメントシェーダの生成
var v_shader = create_shader('vs');
var f_shader = create_shader('fs');
var prg = create_program(v_shader, f_shader);
var attLocation = gl.getAttribLocation(prg, 'position');
var attStride = 3;
// モデルデータ(頂点座標)
var vertex_position = [
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
];
// VBOの生成
var vbo = create_vbo(vertex_position);
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.enableVertexAttribArray(attLocation);
gl.vertexAttribPointer(attLocation, attStride, gl.FLOAT, false, 0, 0);
次頁に続く→
polygon.js (1/2)表示結果
1-2.WebGLは高速/高機能だが実装が大変
Advanced Tech Night
7
// minMatrix.js を用いた行列関連処理
// matIVオブジェクトを生成
var m = new matIV();
var mMatrix = m.identity(m.create());
var vMatrix = m.identity(m.create());
var pMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create());
m.lookAt([0, 0, 1.5], [0, 0, 0], [0, 1, 0], vMatrix);
m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
m.multiply(pMatrix, vMatrix, mvpMatrix);
m.multiply(mvpMatrix, mMatrix, mvpMatrix);
var uniLocation = gl.getUniformLocation(prg, 'mvpMatrix');
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
// モデルの描画
gl.drawArrays(gl.TRIANGLES, 0, 3);
gl.flush();
// シェーダを生成する関数
function create_shader(id) {
var shader;
var scriptElement = document.getElementById(id);
if (!scriptElement){ return; }
switch(scriptElement.type){
case 'x-shader/x-vertex':
shader = gl.createShader(gl.VERTEX_SHADER);
break;
case 'x-shader/x-fragment':
shader = gl.createShader(gl.FRAGMENT_SHADER);
break;
default :
return;
}
gl.shaderSource(shader, scriptElement.text);
gl.compileShader(shader);
polygon.js (2/2)
JavaScriptのコード行数:
→100行
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
return shader;
} else {
alert(gl.getShaderInfoLog(shader));
}
}
// プログラムオブジェクトを生成しシェーダをリンクする関数
function create_program(vs, fs){
var program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
gl.useProgram(program);
return program;
} else {
alert(gl.getProgramInfoLog(program));
}
}
// VBOを生成する関数
function create_vbo(data){
var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data),
gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vbo;
}
};
ちょっとした図形を書くだけなのに、
こんなにコードを書かなければならないなんて...
1-2.WebGLは高速/高機能だが実装が大変
3. OpenGL/WebGLの3D独特な概念は理解が難しい
(頂点配列、シェーダー、視錐体…??)
Advanced Tech Night
8
補助ライブラリを使うべし
1-3.Three.jsで、WebGLを使う
 Three.js
① Three.jsはWebGLの冗長な仕様をうまくラップし、
扱いやすいインターフェイスで提供するライブラリ。
② Mr.Doob氏を中心にオープンソースで開発が進め
られており、WebGL界隈ではデファクトスタンダー
ドに近い地位を築いている。
③ WebGL非サポート環境用としてCanvasやSVGで
のレンダリングも可能で、WebGLまたはWebでの
3D表現の入門用にはうってつけのライブラリとい
える。
Advanced Tech Night
9
http://mrdoob.github.io/three.js/
2.Three.jsでWebGLを使ってみよう
Advanced Tech Night No.7
3DCGをWebGLで始めよう!
Advanced Tech Night
10
2-1.Three.jsでポリゴンを描画してみる
Advanced Tech Night
11
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebGL polygon sample (three.js)</title>
<style type="text/css">
div#canvas-frame{
border: none;
cursor: pointer;
width: 600px;
height: 600px;
background-color: #EEEEEE;
}
</style>
<script src="three.min.js"></script>
<script src="polygon_three.js"></script>
</head>
<body onload="threeStart();">
<div id="canvas-frame"></div>
</body>
</html>
JavaScriptを読み込む
Canvasを用意して、ロード時に
スクリプトを実行する
polygon_three.html
600x600 pxのCanvasを作る
// 光源を生成
light = new THREE.DirectionalLight(0xFF0000, 1.0, 0);
light.position.set(100, 100, 200);
scene.add(light);
}
// オブジェクトを生成する
function initObject(){
plane = new THREE.Mesh(
new THREE.PlaneGeometry(50,50,1,2),
new THREE.MeshLambertMaterial({color: 0xff0000})
);
scene.add(plane);
plane.position.set(0,0,0);
}
// 描画をスタートする
function threeStart() {
initThree();
initObject();
renderer.clear();
renderer.render(scene, camera);
}
2-1.Three.jsでポリゴンを描画してみる
Advanced Tech Night
12
polygon_three.js
平面を指定するGeometry
JavaScriptのコード行数:
→ 48行
HTMLのonloadで実行される
var renderer;
var camera;
var scene;
var light;
var ambient;
var plane;
// Three.jsを初期化し、カメラ、シーン、光源を準備する
function initThree() {
// Three.jsを初期化
width = document.getElementById('canvas-frame').clientWidth;
height = document.getElementById(‘canvas-frame’).clientHeight;
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
document.getElementById(‘canvas-frame’)
.appendChild(renderer.domElement);
renderer.setClearColorHex(0xcccccc, 1.0);
// シーンを生成
scene = new THREE.Scene();
// カメラを生成
camera = new THREE.PerspectiveCamera(45,width/height,1,10000);
camera.position.x = 100;
camera.position.y = 20;
camera.position.z = 50;
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.lookAt({x:0, y:0, z:0});
scene.add(camera);
2-1.Three.jsでポリゴンを描画してみる
Advanced Tech Night
13
こんな感じになりました。
2-2.立方体を書いて、ぐるぐる回してみる
Advanced Tech Night
14
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebGL cube sample (three.js)</title>
<style type="text/css">
div#canvas-frame{
border: none;
cursor: pointer;
width: 600px;
height: 600px;
background-color: #EEEEEE;
}
</style>
<script src="three.min.js"></script>
<script src=“cube_three.js"></script>
</head>
<body onload="threeStart();">
<div id="canvas-frame"></div>
</body>
</html>
JavaScriptを読み込む
(名前変えただけ)
cube_three.html
2-2.立方体を書いて、ぐるぐる回してみる
Advanced Tech Night
15
cube_three.js
図形の変更はGeometryの
種類を変えるだけ
var renderer;
var camera;
var scene;
var light;
var ambient;
var cube;
var baseTime;
// Three.jsを初期化し、カメラ、シーン、光源を準備する
function initThree() {
// Three.jsを初期化
width = document.getElementById('canvas-frame').clientWidth;
height = document.getElementById(‘canvas-frame’).clientHeight;
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
document.getElementById(‘canvas-frame’)
.appendChild(renderer.domElement);
renderer.setClearColorHex(0xcccccc, 1.0);
// シーンを生成
scene = new THREE.Scene();
// カメラを生成
camera = new THREE.PerspectiveCamera(45,width/height,1,10000);
camera.position.x = 100;
camera.position.y = 20;
camera.position.z = 50;
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.lookAt({x:0, y:0, z:0});
scene.add(camera);
// 光源を生成
light = new THREE.DirectionalLight(0xFF0000, 1.0, 0);
light.position.set(100, 100, 200);
scene.add(light);
ambient = new THREE.AmbientLight(0x663333);
ambient.position.set(100, 100, 200);
scene.add(ambient);
}
// オブジェクトを生成する
function initObject() {
cube = new THREE.Mesh(
new THREE.CubeGeometry(50,50,50),
new THREE.MeshLambertMaterial({color: 0xff0000})
);
scene.add(cube);
plane.position.set(0,0,0);
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
cube.rotation.y = 0.3 * (+new Date - baseTime) / 1000;
cube.rotation.z = 0.3 * (+new Date - baseTime) / 1000;
renderer.render(scene, camera);
};
// 描画をスタートする
function threeStart() {
initThree();
initObject();
renderer.clear();
baseTime = +new Date;
render();
}
こっち半分は、
ポリゴンと一緒
立方体/長方体に変更
→クラスを変えるだけ
グルグル回転させる
(JavaScriptのアニメーション機構)
2-2.立方体を書いて、ぐるぐる回してみる
こんな感じになりました。(動かしてみましょう)
Advanced Tech Night
16
2-3.ここまでのまとめ!
Three.jsを使ってWebGL 3D表示を始めるには
Advanced Tech Night
17
1.Three.jsを初期化する!
2.シーンを生成する!
3.カメラを生成する!
4.光源を生成する!
5.オブジェクトを生成する!
あとは、
好きなだけ
グリグリ
しちゃって
ください
6.レンダラで描画する!
世の中にある
demoを
見てみよう
Advanced Tech Night
18
3.WebGLを使う場合の注意点
Advanced Tech Night No.7
3DCGをWebGLで始めよう!
Advanced Tech Night
19
3.WebGLを使う場合の注意点
1. 環境上の制限
① ブラウザのサポート状況(PC)
• デスクトップではほぼサポート/IEは11でようやく
• ただし、ビデオカードでOpenGL2.0の対応が必要
② ブラウザのサポート状況(Android/iPhone)
• Androidは動くけれど設定変更必要+やはり遅い
• iOS(Safari)はごめんなさい
Advanced Tech Night
20
ブラウザ IE FireFox Chrome Opera Safari
サポート 11~ 4~ 8~
(9から標準)
12~
(15から標準)
5.1~
ブラウザ - FireFox Chrome Opera Safari(iOS)
サポート - 4~ 25~ 12~
(15から標準)
×
3.WebGLを使う場合の注意点
2. 機能上の制限
① 凸角形しか作れない。裏表がある
a. Canvasのように凹角形のデータは作れない。
Three.jsでも同様。
b. 凹角形や、中空のモデルを表示するためには、
面分割をしてくれる補助ライブラリ(→後述)が必要。
② Three.jsは楽だが、細かい調整は苦手
a. 提供されているモデルを変形させられないため、
凝ったモデルを表示するには別途頂点データが必要。
→変形させたモデルでも、モデルローダーを使うことに
③ デバッグが大変
Advanced Tech Night
21
3.WebGLを使う場合の注意点
3. 実装上の注意
① JavaScriptに極力処理させない
グラフィックカードの処理の方が圧倒的に早い。
→グラフィックカードにできるだけ処理を任せる。
② データをなるべく転送しない
遅さにつながるWebGLでの暗黙の変換。
→ビデオカードも大きなメモリを持っているので、
極力メモリ上で管理する。
Advanced Tech Night
22
4.ライブラリの紹介
Advanced Tech Night No.7
3DCGをWebGLで始めよう!
Advanced Tech Night
23
4.ライブラリの紹介
1. Three.js → 前述のとおり
2. subdivision関連
3. シェーディング周り
4. モデルローダー
Advanced Tech Night
24
4.ライブラリの紹介
2. subdivision関連
① 前述のとおり、WebGLでは凹角形や中空の
モデルは作れない。ではどうするか?
→凹角形のモデルを、細かい三角形
(必ず凸になる)のポリゴンに分割
する(=subdivisioning)
② 有名なsubdivisionライブラリ
• poly2tri
Advanced Tech Night
25
https://code.google.com/p/poly2tri/
凹角形
中空
4.ライブラリの紹介
3. シェーディングライブラリ
① WebGLはデフォルトのシェーダーを持たない。
→Three.jsは代表的なシェーダーを提供している
が、複雑なシェーディングを行おうとすると、
独自のシェーダーが必要となる。
→イチからシェーダーを定義せずに、ライブラリを
使うのが楽。
② 有名なシェーディングライブラリ
• GLOW
Advanced Tech Night
26
http://i-am-glow.com/
4.ライブラリの紹介
4. モデルローダー
① 3Dモデリングソフトなどで作った頂点データを
WebGL/three.jsに読み込むためのローダー。
② 有名なモデルローダー
• webgl-loader
Advanced Tech Night
27
https://code.google.com/p/webgl-loader/
5.まとめ
1.WebGLを使うことで、ブラウザ上で
高速な3D描画を実現できる。
2.生で使うには実装が煩雑。Three.js
など、補助ライブラリを活用しよう。
3.3Dだからこそできる表現を、簡単に
実現してインタラクティブなUXを!
Advanced Tech Night
28
Copyright © Acroquest Technology Co., Ltd. All rights reserved.
29
ご清聴有難うございました。
Infrastructures Evolution

3DCG(3Dコンピュータグラフィック)をWebGLで始めよう