①環境構築、
②拡散・波動編
予定されている続編:
量子力学編、電磁気学編、流体力学編、物理エンジン開発編(2014年6月予定)
①上巻、
②下巻
ネイティブアプリケーションとウェブアプリケーションの
境目がなくなる基盤技術
平面画像(2次元グラフィックス)や立体感のある画像
(3次元グラフィックス)をコンピュータ内で表現
ウェブブラウザの高機能化の結果、
アプリケーション開発に必要な三要素
【入力】【演算】【出力】
が高レベルで揃う!
グラフィックスの役割 → 文章の補佐
div要素による長方形の重ねあわせ
任意のピクセルに任意の色で描画することができる
→ 原理的には任意の形状の描画可能!(グラデーション)
| 種類 | 利用する要素 | 解説 |
|---|---|---|
| Canvas 2D Context | canvas要素 | 2次元グラフィックスを描画するためのAPI。JavaScriptでAPIを制御。 |
| WebGL Context | canvas要素 | 3次元グラフィックスを描画するためのAPI。JavaScriptでAPIを制御。 |
| SVG | svg要素 | ベクトル形式の画像を出力するための形式。HTML要素の属性値で図形を表現する。 |
| 項目 | Canvas 2D Context (Canvas2D) |
WebGL Context (WebGL) |
|---|---|---|
| 演算 | CPU | GPU |
| 難易度 | 比較的易しい | 非常に難しい |
| ライブラリ | 特に必要なし | three.jsなど |
| 描画速度 | △ | ◎ |
| 描画品質 | ◎ | ◎ |
| 実行環境 | ◎ | ×→○ |
2013年、IE11 が WebGL に対応!!
カウリング(背面処理)、シェーディング(陰影処理)、ブレンディング(混合処理)、テクスチャマッピングなど、
3次元グラフィックスで必要な演算 を半自動的に実行
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>三角形の描画:WebGL</title>
<script src="javascript/glMatrix-0.9.5.min.js"></script>
<style>
*{padding:0px; margin:0px}
canvas#frame{
width: 300px; /* 横幅を指定 */
height: 300px; /* 縦幅を指定 */
}
</style>
<script id="shader-vs" type="x-shader/x-vertex">
//バーテックス・シェーダ
attribute vec3 aVertexPosition; //WebGL中で定義されたattribute変数(頂点座標)
attribute vec4 aVertexColor; //WebGL中で定義されたattribute変数(頂点色)
uniform mat4 uMVMatrix; //WebGL中で定義されたuniform変数(モデルビュー行列)
uniform mat4 uPMatrix; //WebGL中で定義されたuniform変数(プロジェクション行列)
varying vec4 vColor; //フラグメントシェーダに送るvarying変数(vColor)
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
//フラグメントシェーダ
precision mediump float;
varying vec4 vColor; //バーテックスシェーダから受け渡される変数
void main(void) {
gl_FragColor = vColor;
}
</script>
<script>
////////////////////////////////////////////////////////////////////
// windowイベントの定義
////////////////////////////////////////////////////////////////////
window.addEventListener("load", function () {
resizeTo(316, 341);
webGLStart();
});
////////////////////////////////////////////////////////////////////
// 描画開始関数の定義
////////////////////////////////////////////////////////////////////
function webGLStart() {
var canvas = document.getElementById("frame");
canvas.width = canvas.clientWidth; //描画横幅の指定
canvas.height = canvas.clientHeight; //描画縦幅の指定
initGL(canvas);
initialize();
display();
}
////////////////////////////////////////////////////////////////////
// WebGLの初期化
////////////////////////////////////////////////////////////////////
var gl; //WebGLコンテクストオブジェクト
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {}
if (!gl) {
alert("コンテキストの取得に失敗しました");
}
}
//シェーダーの準備
function getShader(gl, id) { //シェーダの読み込み
var shaderScript = document.getElementById(id); //
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {//シェーダ言語の読み込み
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
//シェーダーオブジェクト
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
//シェーダープログラムソースの読み込み
gl.shaderSource(shader, str);
// シェーダーのコンパイル
gl.compileShader(shader);
//コンパイルエラーの場合の処理
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
//シェーダープログラムオブジェクト
var shaderProgram;
//モデルビュー行列
var mvMatrix = mat4.create();
//プロジェクション行列
var pMatrix = mat4.create();
////////////////////////////////////////////////////////////////////
// 各種バッファーの初期化
////////////////////////////////////////////////////////////////////
//バッファー
var positionBuffer; //頂点位置
var colorBuffer; //頂点色
var indexBuffer; //インデックス
function initialize() {
//シェーダー
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
//シェーダープログラムの生成
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, fragmentShader);
gl.attachShader(shaderProgram, vertexShader);
//シェーダープログラムをリンク
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
// シェーダプログラムの適用
gl.useProgram(shaderProgram);
//バーテックスシェーダで利用するattribut変数(頂点位置)を宣言する
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
//バーテックスシェーダで利用するattribut変数(カラー変数)を宣言する
shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
//バーテックスシェーダで利用するuniform変数を宣言する
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
//////////////////三角形のバッファ/////////////////////////////
//頂点バッファ―の設定
vertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
var vertices = [
-45, -45, 0,
45, -45, 0,
0, 45, 0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
vertexPositionBuffer.itemSize = 3;
vertexPositionBuffer.numItems = 3;
//カラーバッファ―の設定
vertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
var colors = [
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
vertexColorBuffer.itemSize = 4;
vertexColorBuffer.numItems = 3;
//インデックスバッファ―の設定
vertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
var indices = [
0, 1, 2
];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
vertexIndexBuffer.itemSize = 1;
vertexIndexBuffer.numItems = 3;
//クリアーカラーの設定
gl.clearColor(0.93, 0.93, 0.93, 1.0);
//デプステストの有効化
gl.enable(gl.DEPTH_TEST);
//ビューポートの設定
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
//プロジェクション行列の設定
mat4.identity(pMatrix);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 1000.0, pMatrix);
//モデルビュー行列の設定
mat4.identity(mvMatrix);
mat4.lookAt(
vec3.create([ 0, 0, 130 ]), //カメラの位置座標
vec3.create([ 0, 0, 0 ]), //カメラの視野中心座標
vec3.create([ 0, 1, 0 ]), //カメラの上座標
mvMatrix
);
}
///////////////////////////////////////////////
//三角形の描画
///////////////////////////////////////////////
function display() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, vertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
//uniform型変数の値を設定する
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix); //プロジェクション行列
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix); //モデルビュー行列
//インデックスバッファーを使って描画する
gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
}
</script>
</head>
<body>
<canvas id="frame" ></canvas>
</body>
</html>
| HTML関連 | 約30行 |
| WebGLの初期化関連 | 約60行 |
| バッファー関連 | 約60行 |
| 形状の指定と描画 | 約30行+約20行 |
| シェーダープログラム | 約30行 |
頂点座標、頂点色、頂点法線ベクトル、テクスチャ座標、
面指定インデックス、面法線ベクトル
プロジェクション行列、モデル行列、ビュー行列
バーテックスシェーダー、フラグメントシェーダ-
ベクトル内積・外積、行列積、逆行列、転置行列、対角化、オイラー角
レンダラーの変更で、同一コードのまま WebGL と Canvas2D を切り替え可能!
将来的には、SVG や CSS3 も同一コードでサポート!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>three.js:三角形の描画</title>
<script src="javascript/three.js_r58/three.js"></script> <!-- Three.js用ライブラリ -->
<style>
*{padding:0px; margin:0px}
div#canvas-frame{
width: 200px; /* 横幅 */
height: 200px; /* 縦幅 */
}
</style>
<script>
////////////////////////////////////////////////////////////////////
// windowイベントの定義
////////////////////////////////////////////////////////////////////
window.addEventListener("load", function () {
resizeTo(216, 241);
threeStart(); //Three.jsのスタート関数の実行
});
function threeStart() {
////////////////////下準備/////////////////////////////////
//キャンバスフレームDOM要素の取得
var canvasFrame = document.getElementById('canvas-frame');
//レンダラーオブジェクトの生成
var renderer = new THREE.WebGLRenderer();
//レンダラーのサイズの設定
renderer.setSize(canvasFrame.clientWidth, canvasFrame.clientHeight);
//キャンバスフレームDOM要素にcanvas要素を追加
canvasFrame.appendChild(renderer.domElement);
//レンダラークリアーカラーの設定
renderer.setClearColor(0xEEEEEE, 1.0);
//シーンオブジェクトの生成
var scene = new THREE.Scene();
////////////////////カメラの準備/////////////////////////////////
//カメラオブジェクトの生成
var camera = new THREE.PerspectiveCamera(45, canvasFrame.clientWidth / canvasFrame.clientHeight, 1, 10000);
//カメラの位置の設定
camera.position.set(0, 0, 130);
//カメラの上ベクトルの設定
camera.up.set(0, 1, 0);
//カメラの中心位置ベクトルの設定
camera.lookAt({ x: 0, y: 0, z: 0 });
////////////////////三角形の準備/////////////////////////////////
//形状オブジェクトの宣言と生成
var geometry = new THREE.Geometry();
//頂点座標データの追加
geometry.vertices[0] = new THREE.Vector3(-45, -45, 0);
geometry.vertices[1] = new THREE.Vector3( 45, -45, 0);
geometry.vertices[2] = new THREE.Vector3( 0, 45, 0);
//面指定用頂点インデックスを追加
geometry.faces[0] = new THREE.Face3(0, 1, 2);
//材質オブジェクトの宣言と生成
var material = new THREE.MeshBasicMaterial({ color: 0xFF0000 });
//三角形オブジェクトの生成
triangle = new THREE.Mesh(geometry, material);
//三角形オブジェクトのシーンへの追加
scene.add(triangle);
//三角形オブジェクトの位置座標を設定
triangle.position.set(0, 0, 0);
////////////////////レンダリング/////////////////////////////////
//クリアーカラーで初期化
renderer.clear();
//レンダリング
renderer.render(scene, camera);
}
</script>
</head>
<body>
<div id="canvas-frame"></div><!-- canvas要素を配置するdiv要素 -->
</body>
</html>
| HTML関連 | 約20行 |
| three.jsの初期化 | 約20行 |
| カメラの準備 | 約5行 |
| 形状と材質の指定から描画まで | 約5行+1行+約4行 |
| レンダリング関連 | 約5行 |



公式ページからライブラリ全体をダウンロードします。
「examples」フォルダにある「webgl_geometries.html」をウェブブラウザで表示し、動作するかを確認します。
Cross-origin image load denied by Cross-Origin Resource Sharing policy.
ローカルに存在するファイル読み込み時に発生するエラー
ウェブサーバー上で同一オリジンの外部ファイル
→ エラーにはならない
--allow-file-access-from-files