【序章】
HTML5による
コンピュータグラフィックス入門

  • 自己紹介
  • HTML5とグラフィックス
  • WebGL と three.js
  • three.js のはじめかた

自己紹介

  • 遠藤理平
  • 大阪生まれ35歳。兵庫 → 福岡 → 新潟 → 仙台19年。
  • 博士(理学)。フォトニック結晶中における光パルスの伝搬(理論)。
  • 2005年、有限会社FIELD AND NETWORK 設立。
  • 2006年、特定非営利活動法人natural science 設立。
  • 利酒道二段。第32回全国きき酒選手権大会出場(平成24年宮城県代表)。平成25年宮城県大会決勝大会敗退。

学都「仙台・宮城」サイエンス・デイ

ものづくり講座

学都「仙台・宮城」サイエンス・コミュニティ

最近の仕事

HTML5による物理シミュレーション

①環境構築、②拡散・波動編

予定されている続編:
量子力学編、電磁気学編、流体力学編、物理エンジン開発編(2014年6月予定)

three.jsによるHTML5 3Dグラフィックス

①上巻、 ②下巻

最近の仕事2

ドラマ「ガリレオ」の小道具として採用

  • 自己紹介
  • HTML5とグラフィックス
  • WebGL と three.js
  • three.js のはじめかた

HTML5とは?

  • ウェブブラウザ上で動作するマークアップ言語
  • 1990年、研究者同士のコミュニケーションツールとして開発される(スイス、欧州合同素粒子原子核研究機構)
  • 最新バージョンはHTML5(2013年現在)
  • スマートフォン、タブレット型PCなど表示端末デバイスやOSの多様化に対するクロスプラットフォーム環境
  • canvas要素、video要素などマルチメディア機能の大幅強化。 → ネイティブアプリケーションを凌ぐAPI群が整備
  • HTML5はウェブページ作成言語からアプリケーション作成言語へ。ウェブブラウザの高機能化→ OS化

ネイティブアプリケーションとウェブアプリケーションの
境目がなくなる基盤技術

コンピュータ・グラフィックスとは?

平面画像(2次元グラフィックス)立体感のある画像
(3次元グラフィックス)
をコンピュータ内で表現

3次元グラフィックスの実装

  • OpenGL(標準化団体 Khronos Group によって策定:Windows、Mac、Linuxなどの種々の環境で動作するクロスプラットフォーム技術
  • DirectX(Microsoft社によって開発:Windowsのみ)

3次元グラフィックスとは?

  • 仮想3次元空間内のオブジェクト
    → 2次元平面(ディスプレイ)への射影(行列計算)
  • グラフィックカード(GPU+メモリ)によるハードウェアアクセラレーションが必須

ウェブブラウザで
コンピュータ・グラフィックス?

ウェブブラウザの高機能化の結果、
アプリケーション開発に必要な三要素
【入力】【演算】【出力】
が高レベルで揃う!

HTML4におけるグラフィックス

グラフィックスの役割 → 文章の補佐

次の三角形の描画するための方法は?

  • 静止画
    (png, jpg, gifなど)
     → img要素
  • 奥の手
     → DHTML
    (ダイナミックHTML)

DHTMLとは?

  • 任意の要素をJavascriptで制御する技術
  • CSS(スタイルシート)で視覚情報を加えることで、グラフィックスとしての利用も可能

DHTMLによる三角形

DHTMLによる三角形

div要素による長方形の重ねあわせ

任意のピクセル任意の色で描画することができる
 → 原理的には任意の形状の描画可能!(グラデーション

HTML5におけるグラフィックス

種類 利用する要素 解説
Canvas 2D Context canvas要素 2次元グラフィックスを描画するためのAPI。JavaScriptでAPIを制御。
WebGL Context canvas要素 3次元グラフィックスを描画するためのAPI。JavaScriptでAPIを制御。
SVG svg要素 ベクトル形式の画像を出力するための形式。HTML要素の属性値で図形を表現する。

Canvas 2D Context と WebGL Context

Canvas 2D Context と
WebGL Context

項目 Canvas 2D Context
(Canvas2D)
WebGL Context
(WebGL)
演算 CPU GPU
難易度 比較的易しい 非常に難しい
ライブラリ 特に必要なし three.jsなど
描画速度
描画品質
実行環境
×→○

2013年、IE11 が WebGL に対応!!

  • 自己紹介
  • HTML5とグラフィックス
  • WebGL と three.js
  • three.js のはじめかた

WebGLとは?

  • OpenGL ES2.0 をウェブブラウザ上で動作させる API。
  • グラフィックカードをフルに活用(GPU+メモリ)
     →ウェブブラウザでハードウェア資源へのアクセス権
  • 現在のバージョンは 1.0.1。
  • OpenGL と同様、Khronos Group によって策定。

WebGL(OpenGL)の利点

カウリング(背面処理)、シェーディング(陰影処理)、ブレンディング(混合処理)、テクスチャマッピングなど、

3次元グラフィックスで必要な演算 を半自動的に実行

WebGLによる三角形

プログラムソース

	<!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>
	

プログラムの内訳(全:230行)

HTML関連約30行
WebGLの初期化関連約60行
バッファー関連約60行
形状の指定と描画約30行+約20行
シェーダープログラム約30行

WebGLの問題点:難しい!!

頂点バッファーの管理

頂点座標、頂点色、頂点法線ベクトル、テクスチャ座標、
面指定インデックス、面法線ベクトル

行列演算の管理

プロジェクション行列、モデル行列、ビュー行列

シェーダー言語の記述

バーテックスシェーダー、フラグメントシェーダ-

各種ベクトル・行列・クォータニオン演算

ベクトル内積・外積、行列積、逆行列、転置行列、対角化、オイラー角

three.js の登場!!

  • 2010年4月、Mr.doob 氏によって公開開始(r1)。
  • 2013年12月の最新リビジョンは63(r63)。
  • WebGLにおけるめんどくさいところを全てラッピング。
  • WebGLにおけるjQuery的な存在。
  • コンピュータ・グラフィックスを直感的に実装可能。
  • WebGLにおけるネイティブ領域を制御可能。

three.jsのすごさ

レンダラーの変更で、同一コードのまま WebGLCanvas2D を切り替え可能!

将来的には、SVGCSS3 も同一コードでサポート!

three.jsによる三角形

プログラムソース

	<!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>
	

プログラムの内訳(全:60行)

HTML関連約20行
three.jsの初期化約20行
カメラの準備約5行
形状と材質の指定から描画まで約5行+1行+約4行
レンダリング関連約5行

three.js公式ウェブページ

URL : http://threejs.org/

three.js公式サンプル

three.js公式ドキュメント

  • 自己紹介
  • HTML5とグラフィックス
  • WebGL と three.js
  • three.js のはじめかた

three.jsを学ぶのに必要な知識

HTML:レベル1でOK!

  • 要素や属性の意味(div要素、script要素など、id属性やclass属性など)

CSS:レベル1でOK!

  • プロパティの意味(widthプロパティ、height:プロパティなど)と値の与え方

JavaScript:レベル3が必要!

  • レベル1:ステートメント(var, for, if, function, Array, Object, new など)
  • レベル2:オブジェクトの構造、イベントの管理、無名関数、メソッドチェーンなどのJavaScript特有の仕様
  • レベル3:クラス関連(コンストラクタ、メソッド、プロパティなど)の理解

three.js のはじめかた

three.jsの取得

公式ページからライブラリ全体をダウンロードします。

動作確認

「examples」フォルダにある「webgl_geometries.html」をウェブブラウザで表示し、動作するかを確認します。

テクスチャマッピングが怪しい

Consoleの出力内容

Cross-origin image load denied by Cross-Origin Resource Sharing policy.

実行時の注意

ローカルに存在するファイル読み込み時に発生するエラー

  • テクスチャマッピング用の画像ファイル
  • WebWordersのワーカーファイルなど

ウェブサーバー上で同一オリジンの外部ファイル
 → エラーにはならない

回避方法

  • ローカルPC内でウェブサーバーの立ち上げ
  • 起動オプションの設定(GoogleChromeの場合)
      ↑こちらを採用!

起動オプションの設定方法

  1. ソフトウェア起動用ショートカットアイコンの作成
  2. プロパティの表示(右クリック)→ショートカットタブ
  3. リンク先欄の最後に次の文字列を挿入
    --allow-file-access-from-files
  4. 「OK」ボタンをクリック
  5. GoogleChrome を全て終了した後に、ショートカットアイコンで起動

動きましたでしょうか?

three.jsの初め方