1. 行列の基本
行列は、数値の配列であり、特定の変換操作を簡単に表現できます。2Dグラフィックスでは主に3×3行列、3Dグラフィックスでは4×4行列を使用します。
3x3行列:
[a, b, c,d, e, f,
g, h, i]
4×4行列:
[a, b, c, d,e, f, g, h,
i, j, k, l,
m, n, o, p]
2. 平行移動行列 (Translation)
平行移動行列は、オブジェクトを特定の方向に移動させます。以下は、2Dと3Dの平行移動行列です。
2D平行移動行列
2D平行移動行列は、x方向とy方向にオブジェクトを移動させます。
[1, 0, tx,
0, 1, ty,
0, 0, 1]
txとtyはそれぞれx方向とy方向の移動距離です。
3D平行移動行列
3D平行移動行列は、x方向、y方向、z方向にオブジェクトを移動させます。
[1, 0, 0, tx,
0, 1, 0, ty,
0, 0, 1, tz,
0, 0, 0, 1]
tx、ty、tzはそれぞれx方向、y方向、z方向の移動距離です。
3. 回転行列 (Rotation)
回転行列は、オブジェクトを特定の軸の周りに回転させます。以下は、2Dと3Dの回転行列です。
2D回転行列
2D回転行列は、原点を中心にオブジェクトを回転させます。
[cos(θ), -sin(θ), 0,
sin(θ), cos(θ), 0,
0, 0, 1]
θは回転角度です。
3D回転行列
3D回転行列は、X軸、Y軸、Z軸の周りにオブジェクトを回転させます。
X軸回転行列
[1, 0, 0, 0,
0, cos(θ), -sin(θ), 0,
0, sin(θ), cos(θ), 0,
0, 0, 0, 1]
Y軸回転行列
[ cos(θ), 0, sin(θ), 0,
0, 1, 0, 0,
-sin(θ), 0, cos(θ), 0,
0, 0, 0, 1]
Z軸回転行列
[cos(θ), -sin(θ), 0, 0,
sin(θ), cos(θ), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]
4. スケーリング行列 (Scaling)
スケーリング行列は、オブジェクトのサイズを変更します。以下は、2Dと3Dのスケーリング行列です。
2Dスケーリング行列
2Dスケーリング行列は、x方向とy方向にオブジェクトのサイズを変更します。
[sx, 0, 0,
0, sy, 0,
0, 0, 1]
sxとsyはそれぞれx方向とy方向のスケーリングファクターです。
3Dスケーリング行列
3Dスケーリング行列は、x方向、y方向、z方向にオブジェクトのサイズを変更します。
[sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
0, 0, 0, 1]
sx、sy、szはそれぞれx方向、y方向、z方向のスケーリングファクターです。
5. 実際のWebGLでの使用例
次に、これらの行列を使った実際のWebGLでの使用例を示します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>WebGL 行列の使用例</title>
</head>
<body>
<canvas id="webgl-canvas" width="640" height="480"></canvas>
<script>
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) {
alert('WebGLをサポートしていません');
throw new Error('WebGL not supported');
}
// シェーダープログラムの作成
const vertexShaderSource = `
attribute vec4 a_Position;
uniform mat4 u_ModelMatrix;
void main() {
gl_Position = u_ModelMatrix * a_Position;
}
`;
const fragmentShaderSource = `
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;
}
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));
gl.deleteProgram(program);
return;
}
gl.useProgram(program);
// 四角形の頂点データ
const vertices = new Float32Array([
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, 0.5, 0.0,
0.5, -0.5, 0.0
]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(program, 'a_Position');
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
// 変換行列の作成
function getTranslationMatrix(tx, ty, tz) {
return new Float32Array([
1.0, 0.0, 0.0, tx,
0.0, 1.0, 0.0, ty,
0.0, 0.0, 1.0, tz,
0.0, 0.0, 0.0, 1.0
]);
}
function getRotationMatrix(angle) {
const rad = angle * Math.PI / 180;
const cos = Math.cos(rad);
const sin = Math.sin(rad);
return new Float32Array([
cos, -sin, 0.0, 0.0,
sin, cos, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
]);
}
function getScalingMatrix(s行列を用いてWebGLでの3Dグラフィックスを制御する方法を、平行移動、回転、スケーリングの行列を使って説明します。
### 平行移動行列(Translation Matrix)
オブジェクトを特定の位置に移動させるために使用します。
```javascript
function getTranslationMatrix(tx, ty, tz) {
return new Float32Array([
1.0, 0.0, 0.0, tx,
0.0, 1.0, 0.0, ty,
0.0, 0.0, 1.0, tz,
0.0, 0.0, 0.0, 1.0
]);
}
この行列は、x方向、y方向、z方向にtx
, ty
, tz
だけ移動します。
回転行列(Rotation Matrix)
オブジェクトを特定の軸の周りに回転させるために使用します。
Z軸回転行列の例
function getRotationMatrix(angle) {
const rad = angle * Math.PI / 180;
const cos = Math.cos(rad);
const sin = Math.sin(rad);
return new Float32Array([
cos, -sin, 0.0, 0.0,
sin, cos, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
]);
}
この行列は、z軸を中心にangle
度回転します。
スケーリング行列(Scaling Matrix)
オブジェクトのサイズを変更するために使用します。
function getScalingMatrix(sx, sy, sz) {
return new Float32Array([
sx, 0.0, 0.0, 0.0,
0.0, sy, 0.0, 0.0,
0.0, 0.0, sz, 0.0,
0.0, 0.0, 0.0, 1.0
]);
}
この行列は、x方向、y方向、z方向にsx
, sy
, sz
の比率で拡大縮小します。
例:WebGLで行列を使ったシェーダー
次に、平行移動、回転、スケーリング行列を使用してオブジェクトを操作するWebGLの例を示します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>WebGL 行列の使用例</title>
</head>
<body>
<canvas id="webgl-canvas" width="640" height="480"></canvas>
<script>
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) {
alert('WebGLをサポートしていません');
throw new Error('WebGL not supported');
}
// シェーダープログラムの作成
const vertexShaderSource = `
attribute vec4 a_Position;
uniform mat4 u_ModelMatrix;
void main() {
gl_Position = u_ModelMatrix * a_Position;
}
`;
const fragmentShaderSource = `
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;
}
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));
gl.deleteProgram(program);
return;
}
gl.useProgram(program);
// 四角形の頂点データ
const vertices = new Float32Array([
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, 0.5, 0.0,
0.5, -0.5, 0.0
]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(program, 'a_Position');
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
const u_ModelMatrix = gl.getUniformLocation(program, 'u_ModelMatrix');
// 変換行列の作成と適用
let modelMatrix = getTranslationMatrix(0.0, 0.0, 0.0);
modelMatrix = multiplyMatrices(modelMatrix, getRotationMatrix(45));
modelMatrix = multiplyMatrices(modelMatrix, getScalingMatrix(1.0, 1.0, 1.0));
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
// 行列の積を計算する関数
function multiplyMatrices(a, b) {
const result = new Float32Array(16);
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
result[i * 4 + j] = 0;
for (let k = 0; k < 4; k++) {
result[i * 4 + j] += a[i * 4 + k] * b[k * 4 + j];
}
}
}
return result;
}
function getTranslationMatrix(tx, ty, tz) {
return new Float32Array([
1.0, 0.0, 0.0, tx,
0.0, 1.0, 0.0, ty,
0.0, 0.0, 1.0, tz,
0.0, 0.0, 0.0, 1.0
]);
}
function getRotationMatrix(angle) {
const rad = angle * Math.PI / 180;
const cos = Math.cos(rad);
const sin = Math.sin(rad);
return new Float32Array([
cos, -sin, 0.0, 0.0,
sin, cos, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
]);
}
function getScalingMatrix(sx, sy, sz) {
return new Float32Array([
sx, 0.0, 0.0, 0.0,
0.0, sy, 0.0, 0.0,
0.0, 0.0, sz, 0.0,
0.0, 0.0, 0.0, 1.0
]);
}
</script>
</body>
</html>
この例では、平行移動、回転、スケーリング行列を使用して、四角形を操作しています。行列の積を計算して、複合変換を行うことができます。行列の積の計算は、行列同士の要素を掛け合わせて新しい行列を作成することで行います。