①環境構築、②拡散・波動編
予定されている続編:
量子力学編、電磁気学編、流体力学編、物理エンジン開発編(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