【超初学者向け】WebGL超入門〜WebGLの基本を徹底解説〜

WebGLに触れてみよう

記事内に広告を含みます

WebGLの基本概念

WebGLプログラミングを始める前に、いくつかの重要な基本概念を理解しておくことが重要です。これらは3Dグラフィックスを扱う上で共通する考え方であり、WebGLも例外ではありません。

GPUとCPU

コンピュータの頭脳であるCPU(Central Processing Unit)は、汎用的な計算処理を得意とします。一方、GPU(Graphics Processing Unit)は、その名の通りグラフィックス処理に特化したプロセッサです。特に、3Dグラフィックスの描画に必要な大量の並列計算(例えば、何百万もの点の位置や色を同時に計算する)を高速に処理する能力に優れています。

WebGLは、このGPUの能力を最大限に引き出すことで、ウェブブラウザ上で滑らかな3Dグラフィックスを実現しています。CPUは描画に必要なデータ(モデルの形状、テクスチャなど)を準備し、GPUに描画命令を送る役割を担います。GPUはそれらの命令を受け取り、実際に画面に描画する処理を行います。

シェーダー(Shader)

シェーダーは、GPU上で実行される小さなプログラムのことです。WebGLでは、主に2種類のシェーダーを使用します。

•頂点シェーダー(Vertex Shader): 3Dモデルを構成する「頂点」の位置を計算し、画面上のどこに表示するかを決定します。例えば、モデルを回転させたり、拡大縮小したりといった変形処理は、この頂点シェーダーで行われます。

•フラグメントシェーダー(Fragment Shader): 画面上のピクセル(フラグメント)ごとに色を計算します。光の当たり具合やテクスチャの色などを考慮して、最終的なピクセルの色を決定します。これにより、リアルな質感や陰影が表現されます。

これらのシェーダーは、GLSL(OpenGL Shading Language)というC言語に似た専用の言語で記述されます。WebGLでは、JavaScriptからこれらのGLSLプログラムをGPUに送り込み、実行させます。

頂点、プリミティブ、テクスチャ

3Dグラフィックスは、非常にシンプルな要素の組み合わせでできています。

•頂点(Vertex): 3D空間における点の位置情報です。通常、X、Y、Zの3つの座標で表されます。頂点には、色や法線(面の向きを表すベクトル)、テクスチャ座標などの情報も付加されます。

•プリミティブ(Primitive): 頂点を組み合わせて作られる基本的な図形のことです。WebGLでは、主に以下の3種類のプリミティブを扱います。

•点(Points): 1つの頂点からなる点。

•線(Lines): 2つの頂点からなる線分。複数の線分を連結して線を描くこともできます。

•三角形(Triangles): 3つの頂点からなる面。3Dモデルは、この三角形の集合体として表現されます。複雑な曲面も、非常に小さな三角形の集まりとして表現されます。

•テクスチャ(Texture): 3Dモデルの表面に貼り付ける画像のことです。これにより、モデルに色や模様、質感を与えることができます。例えば、木の板のモデルに木のテクスチャを貼り付けることで、よりリアルな木の質感を表現できます。

レンダリングパイプラインの概要

WebGLが3Dグラフィックスを描画する一連の流れは、「レンダリングパイプライン」と呼ばれます。これは、3Dデータを入力として受け取り、最終的に2Dの画像として画面に出力するまでの各段階を指します。大まかな流れは以下の通りです。

1.データ準備: CPUが3Dモデルの頂点データ、テクスチャ、シェーダープログラムなどを準備します。

2.頂点処理: 頂点シェーダーが各頂点の位置を計算し、3D空間から2Dスクリーン上の位置に変換します。

3.プリミティブアセンブリ: 変換された頂点から、点、線、三角形などのプリミティブを組み立てます。

4.ラスタライズ: 組み立てられたプリミティブを、画面上のピクセルに変換します。この段階で、どのピクセルがどのプリミティブに属するかが決定されます。

5.フラグメント処理: フラグメントシェーダーが各ピクセルの最終的な色を計算します。テクスチャの適用や光の計算などが行われます。

6.フレームバッファへの書き込み: 計算されたピクセルの色が、最終的に画面に表示される「フレームバッファ」に書き込まれます。

このパイプラインを高速に処理することで、WebGLはリアルタイムでの3Dグラフィックス描画を可能にしています。

WebGLプログラミングの基礎

ここからは、実際にWebGLを使って簡単な図形を描画するための基本的な手順を見ていきましょう。WebGLプログラミングは、HTMLとJavaScriptを使って行います。

canvasの準備

まず、WebGLの描画領域となるcanvas要素をHTMLファイルに用意します。このcanvas要素が、WebGLが3Dグラフィックスを描画するための「キャンバス」となります。

HTML
<!DOCTYPE html>
<html lang="ja">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>WebGL基本サンプル</title>
</head>
<body> <canvas id="webgl-canvas" width="400" height="400"></canvas> <script src="webgl-sample.js"></script>
</body>
</html>

JavaScriptファイルの準備とWebGLコンテキストの取得

次に、JavaScriptファイルでWebGLの処理を記述します。最初に、HTMLで用意したcanvas要素を取得し、そのcanvasからWebGLの描画コンテキストを取得します。このコンテキストを通じて、WebGLのAPIを呼び出してグラフィックスを描画します。

JavaScript
// Canvas要素を取得
const canvas = document.getElementById('webgl-canvas');
// WebGLコンテキストを取得
const gl = canvas.getContext('webgl');
// WebGLがサポートされているかチェック
if (!gl) { alert('WebGLがサポートされていません'); throw new Error('WebGL not supported');
}

シェーダーの作成とコンパイル

WebGLでは、前述の通り「頂点シェーダー」と「フラグメントシェーダー」が必要です。これらのシェーダーのソースコードをJavaScript内で文字列として定義し、WebGLにコンパイルさせます。

JavaScript
// 頂点シェーダーのソースコード
const vertexShaderSource = ` attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0.0, 1.0); }
`;
// フラグメントシェーダーのソースコード
const fragmentShaderSource = ` precision mediump float; void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 赤色 }
`;
// シェーダーをコンパイルする関数
function createShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { console.error('シェーダーのコンパイルエラー:', gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader;
}

プログラムのリンクと使用

コンパイルされた頂点シェーダーとフラグメントシェーダーをリンクして、一つの「プログラム」を作成します。このプログラムが、GPU上で実行される実際の描画処理の単位となります。

JavaScript
// シェーダーを作成
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
// プログラムを作成してシェーダーをリンク
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
// リンクが成功したかチェック
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error('プログラムのリンクエラー:', gl.getProgramInfoLog(program)); throw new Error('Program link failed');
}
// プログラムを使用
gl.useProgram(program);

頂点データの準備

描画したい図形(例えば三角形)の頂点データをJavaScriptの配列で定義し、それをGPUが扱える形式(バッファオブジェクト)に変換してGPUに送ります。

JavaScript
// 三角形の頂点データ(x, y座標)
const vertices = new Float32Array([ 0.0, 0.5, // 上の頂点 -0.5, -0.5, // 左下の頂点 0.5, -0.5 // 右下の頂点
]);
// バッファを作成して頂点データを送信
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 属性の位置を取得
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
// 属性を有効にして設定
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

描画

最後に、準備したデータとプログラムを使って、実際に図形を描画します。ここでは、クリアカラーの設定や、描画するプリミティブの種類(三角形など)を指定します。

JavaScript
// ビューポートを設定
gl.viewport(0, 0, canvas.width, canvas.height);
// 背景色を設定(黒色)
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 画面をクリア
gl.clear(gl.COLOR_BUFFER_BIT);
// 三角形を描画
gl.drawArrays(gl.TRIANGLES, 0, 3);

これらのステップを経て、ウェブブラウザ上に3Dグラフィックスが表示されることになります。最初は複雑に感じるかもしれませんが、一つ一つのステップを理解していくことで、WebGLプログラミングの面白さがわかってくるでしょう!