IBMのDeveloper Worksにて、WebGLの技術文書が公開されています。
WebGL による 3D 開発: 第 1 回 WebGL の紹介
こちらのページを参考に、WebGLの基礎的なサンプルの実装を行ってみました。
ソースコード
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<title></title>
<script src="gl-matrix.js"></script>
<script id="vertshader" type="x-shader/vertshader">
attribute vec3 vertPos;
attribute vec4 vertColor;
uniform mat4 mvMatrix;
uniform mat4 pjMatrix;
varying lowp vec4 vColor;
void main(void) {
gl_Position = pjMatrix * mvMatrix * vec4(vertPos, 1.0);
vColor = vertColor;
}
</script>
<script id="fragshader" type="x-shader/fragshader">
varying lowp vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
</script>
<script>
var gl = null;
var vertBuffer, colorBuffer;
var shaderProg, shaderVertexPositionAttribute, shaderVertexColorAttribute,
shaderProjectionMatrixUniform, shaderModelViewMatrixUniform;
var modelViewMatrix, rotationAxis, projectionMatrix;
function init() {
// WebGLコンテキストの取得
var canvas = document.getElementById("canvas");
gl = canvas.getContext("webgl");
// ビューポートの設定
gl.viewport(0, 0, canvas.width, canvas.height);
// 頂点バッファの作成
vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
var verts = [
0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0,
0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0,
0.0, 1.0, 0.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
// カラーバッファの作成
colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
var faceColors = [
[0.0, 0.0, 1.0, 1.0], // front (blue)
[1.0, 1.0, 0.0, 1.0], // right (yellow)
[0.0, 1.0, 0.0, 1.0], // back (green)
[1.0, 0.0, 0.0, 1.0], // left (red)
];
var vertColors = [];
faceColors.forEach(function(color) {
[0, 1].forEach(function() {
vertColors = vertColors.concat(color);
});
vertColors = vertColors.concat([1.0, 1.0, 1.0, 1.0]);
});
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertColors), gl.STATIC_DRAW);
// シェーダーコンパイル結果のチェック用関数
var checkShader = function(shader, type) {
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
var errmes = type + " shader compile failed: "
+ gl.getShaderInfoLog(shader);
throw new Error(errmes);
}
};
// 頂点シェーダー
var vertShaderSource = document.getElementById("vertshader").textContent;
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertShaderSource);
gl.compileShader(vertShader);
checkShader(vertShader, "vertex");
// フラグメントシェーダー
var fragShaderSource = document.getElementById("fragshader").textContent;
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragShaderSource);
gl.compileShader(fragShader);
checkShader(fragShader, "fragment");
// シェーダーのリンク
shaderProg = gl.createProgram();
gl.attachShader(shaderProg, vertShader);
gl.attachShader(shaderProg, fragShader);
gl.linkProgram(shaderProg);
// シェーダーのリンクのチェック
if (!gl.getProgramParameter(shaderProg, gl.LINK_STATUS)) {
var errmes = "failed to initialize shader with data matrices";
throw new Error(errmes);
}
// シェーダーパラメータの設定
shaderVertexPositionAttribute = gl.getAttribLocation(shaderProg, "vertPos");
gl.enableVertexAttribArray(shaderVertexPositionAttribute);
shaderVertexColorAttribute = gl.getAttribLocation(shaderProg, "vertColor");
gl.enableVertexAttribArray(shaderVertexColorAttribute);
shaderProjectionMatrixUniform = gl.getUniformLocation(shaderProg, "pjMatrix");
shaderModelViewMatrixUniform = gl.getUniformLocation(shaderProg, "mvMatrix");
// マトリクス
modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [0, 0, -3]);
projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 1, 100);
// 回転軸
rotationAxis = vec3.create();
vec3.normalize(rotationAxis, [0, 1, 0]);
requestAnimationFrame(update);
}
function draw() {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(shaderProg);
// 頂点属性の位置情報の設定
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.vertexAttribPointer(shaderVertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.vertexAttribPointer(shaderVertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
// 行列の設定
gl.uniformMatrix4fv(shaderProjectionMatrixUniform, false, projectionMatrix);
gl.uniformMatrix4fv(shaderModelViewMatrixUniform, false, modelViewMatrix);
// 描画
gl.drawArrays(gl.TRIANGLES, 0, 12 /* num of vertex */);
}
var lastTime = null;
function update(time) {
requestAnimationFrame(update);
var elapsedTime = lastTime ? time - lastTime : 0;
lastTime = time;
// 回転
var angle = Math.PI * elapsedTime / 10000;
mat4.rotate(modelViewMatrix, modelViewMatrix, angle, rotationAxis);
draw();
}
window.addEventListener("load", init);
</script>
</head>
<body>
<canvas id="canvas" width="320" height="240"></canvas>
</body>
</html>
gl-matrix.jsに依存しているので、実行のためには同一ディレクトリにgl-matrix.jsを入れる必要があります。
実行結果は以下のようになります。
ピラミッド型のポリゴンが回転します。
こちらのページでサンプルコードを実際に動かすことができます。(要WebGLに対応した環境)
使用したWebGLの関数と定数
この基礎的なサンプルで使用したWebGLの関数と定数は以下のとおりです。
関数
- createBuffer
- bindBuffer
- bufferData
- getShaderParameter
- getShaderInfoLog
- createShader
- shaderSource
- compileShader
- createProgram
- attachShader
- linkProgram
- getProgramParameter
- getAttribLocation
- enableVertexAttribArray
- getUniformLocation
- clearColor
- enable
- clear
- useProgram
- vertexAttribPointer
- uniformMatrix4fv
- drawArrays
定数
- ARRAY_BUFFER
- STATIC_DRAW
- COMPILE_STATUS
- VERTEX_SHADER
- FRAGMENT_SHADER
- LINK_STATUS
- DEPTH_TEST
- COLOR_BUFFER_BIT
- DEPTH_BUFFER_BIT
- FLOAT
上記のWebGLの関数と定数を理解しておくと、基礎的な部分を理解したと考えても良さそうです。