# 機能設計書: Matrix4（4x4行列/変換行列）

## 1. 機能概要

### 1.1 機能の目的
Matrix4は、4x4行列を表現するためのクラスであり、3Dコンピュータグラフィックスにおける最も重要な数学クラスの一つである。平行移動、回転、スケール、射影など、3D空間における変換を単一の行列で表現し、効率的な座標変換を可能にする。

### 1.2 主な機能
- 4x4行列の基本操作（設定、コピー、転置）
- 行列の乗算、逆行列、行列式計算
- 変換行列の生成（平行移動、回転、スケール、せん断）
- 射影行列の生成（透視投影、平行投影）
- オイラー角、クォータニオンからの回転行列生成
- 位置・回転・スケールの合成と分解
- lookAt行列の生成

### 1.3 関連する画面/コンポーネント
- Object3D（位置、回転、スケールの変換）
- カメラ（ビュー行列、射影行列）
- レンダラー（モデル・ビュー・射影変換）
- スケルタルアニメーション（ボーン変換）

## 2. 機能仕様

### 2.1 データ構造

```javascript
class Matrix4 {
    elements: Array<number>;  // 列優先の16要素配列
    isMatrix4: boolean;       // 型判定フラグ
}
```

### 2.2 行列の格納形式
```
行優先表記（コンストラクタ/set引数）:
| n11  n12  n13  n14 |
| n21  n22  n23  n24 |
| n31  n32  n33  n34 |
| n41  n42  n43  n44 |

列優先格納（elements配列）:
elements = [n11, n21, n31, n41, n12, n22, n32, n42, n13, n23, n33, n43, n14, n24, n34, n44]
           [0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  [9]  [10] [11] [12] [13] [14] [15]
```

### 2.3 メソッド詳細

#### 2.3.1 基本操作
| メソッド | 説明 |
|---------|------|
| set(n11, ..., n44) | 行優先で要素を設定 |
| identity() | 単位行列に設定 |
| clone() | 複製を作成 |
| copy(m) | 他の行列をコピー |
| copyPosition(m) | 位置成分のみコピー |
| setFromMatrix3(m) | 3x3行列から設定 |

#### 2.3.2 行列演算
| メソッド | 説明 |
|---------|------|
| multiply(m) | 後置乗算 (this * m) |
| premultiply(m) | 前置乗算 (m * this) |
| multiplyMatrices(a, b) | a * b の結果を格納 |
| multiplyScalar(s) | 全要素をスカラー乗算 |
| determinant() | 行列式を計算 |
| invert() | 逆行列を計算 |
| transpose() | 転置行列を計算 |

#### 2.3.3 変換行列生成
| メソッド | 説明 |
|---------|------|
| makeTranslation(x, y, z) | 平行移動行列 |
| makeRotationX/Y/Z(theta) | 軸回転行列 |
| makeRotationAxis(axis, angle) | 任意軸回転行列 |
| makeRotationFromEuler(euler) | オイラー角から回転行列 |
| makeRotationFromQuaternion(q) | クォータニオンから回転行列 |
| makeScale(x, y, z) | スケール行列 |
| makeShear(xy, xz, yx, yz, zx, zy) | せん断行列 |

#### 2.3.4 射影行列生成
| メソッド | 説明 |
|---------|------|
| makePerspective(left, right, top, bottom, near, far, coordinateSystem) | 透視投影行列 |
| makeOrthographic(left, right, top, bottom, near, far, coordinateSystem) | 平行投影行列 |

#### 2.3.5 合成・分解
| メソッド | 説明 |
|---------|------|
| compose(position, quaternion, scale) | 位置・回転・スケールから合成 |
| decompose(position, quaternion, scale) | 位置・回転・スケールに分解 |

#### 2.3.6 基底・位置操作
| メソッド | 説明 |
|---------|------|
| extractBasis(xAxis, yAxis, zAxis) | 基底ベクトルを抽出 |
| makeBasis(xAxis, yAxis, zAxis) | 基底ベクトルから行列生成 |
| extractRotation(m) | 回転成分を抽出 |
| setPosition(x, y, z) | 位置成分を設定 |
| lookAt(eye, target, up) | lookAt行列を設定 |

#### 2.3.7 その他
| メソッド | 説明 |
|---------|------|
| scale(v) | 現在の行列にスケールを適用 |
| getMaxScaleOnAxis() | 最大スケール値を取得 |
| equals(m) | 等値比較 |
| fromArray(array, offset) | 配列から設定 |
| toArray(array, offset) | 配列に出力 |

### 2.4 ビジネスルール
- 行列演算は元の行列を変更する（ミュータブル）
- コンストラクタとset()は行優先、内部格納は列優先
- 行列式が0の場合、invert()はゼロ行列を返す
- compose()/decompose()は非一様スケールの親がある場合に不正確

## 3. 処理フロー

### 3.1 compose()フロー
```
[compose(position, quaternion, scale)]
        |
        v
[クォータニオンから回転行列要素計算]
x2 = x + x, y2 = y + y, z2 = z + z
xx = x * x2, xy = x * y2, ...
        |
        v
[スケールを適用]
te[0] = (1 - (yy + zz)) * sx
te[1] = (xy + wz) * sx
...
        |
        v
[位置を設定]
te[12] = position.x
te[13] = position.y
te[14] = position.z
        |
        v
[自身を返却]
```

### 3.2 decompose()フロー
```
[decompose(position, quaternion, scale)]
        |
        v
[位置を抽出]
position.x/y/z = te[12/13/14]
        |
        v
[行列式を確認]
det = determinant()
        |
        v
[det == 0?]
   Yes |         No
       v          |
[デフォルト値]     |
scale=(1,1,1)     v
quaternion=identity
       |   [スケールを計算]
       |   sx = column0.length()
       |   sy = column1.length()
       |   sz = column2.length()
       |   (det < 0 なら sx を反転)
       |          |
       |          v
       |   [回転行列を正規化]
       |   各列をスケールで除算
       |          |
       |          v
       |   [クォータニオンに変換]
       |   quaternion.setFromRotationMatrix()
       |          |
       v          v
[自身を返却]<-----'
```

### 3.3 makePerspective()フロー
```
[makePerspective(left, right, top, bottom, near, far, coordinateSystem)]
        |
        v
[基本パラメータ計算]
x = 2 * near / (right - left)
y = 2 * near / (top - bottom)
a = (right + left) / (right - left)
b = (top + bottom) / (top - bottom)
        |
        v
[座標系に応じたc, d計算]
WebGL: c = -(far + near) / (far - near)
       d = -2 * far * near / (far - near)
WebGPU: c = -far / (far - near)
        d = -far * near / (far - near)
        |
        v
[行列要素を設定]
| x  0  a  0 |
| 0  y  b  0 |
| 0  0  c  d |
| 0  0 -1  0 |
```

## 4. コードリーディングガイド

### 4.1 推奨読解順序
1. **Matrix4.js** - クラス定義とプロパティ（1-97行目）
2. set(), identity(), copy()（99-183行目）
3. compose(), decompose()（1000-1102行目）
4. 射影行列生成（1118-1222行目）
5. 変換行列生成（806-963行目）
6. 行列演算（531-759行目）

### 4.2 重要な処理の詳細

#### コンストラクタ（66-97行目）
```javascript
constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
    Matrix4.prototype.isMatrix4 = true;

    this.elements = [
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    ];

    if ( n11 !== undefined ) {
        this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 );
    }
}
```

#### compose()（1000-1034行目）
```javascript
compose( position, quaternion, scale ) {
    const te = this.elements;

    const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
    const x2 = x + x, y2 = y + y, z2 = z + z;
    const xx = x * x2, xy = x * y2, xz = x * z2;
    const yy = y * y2, yz = y * z2, zz = z * z2;
    const wx = w * x2, wy = w * y2, wz = w * z2;

    const sx = scale.x, sy = scale.y, sz = scale.z;

    te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
    te[ 1 ] = ( xy + wz ) * sx;
    te[ 2 ] = ( xz - wy ) * sx;
    // ... スケール適用済み回転行列

    te[ 12 ] = position.x;
    te[ 13 ] = position.y;
    te[ 14 ] = position.z;
    te[ 15 ] = 1;

    return this;
}
```

#### decompose()（1049-1102行目）
```javascript
decompose( position, quaternion, scale ) {
    const te = this.elements;

    position.x = te[ 12 ];
    position.y = te[ 13 ];
    position.z = te[ 14 ];

    const det = this.determinant();

    if ( det === 0 ) {
        scale.set( 1, 1, 1 );
        quaternion.identity();
        return this;
    }

    let sx = _v1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
    const sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
    const sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();

    if ( det < 0 ) sx = - sx;

    // ... 回転成分の正規化とクォータニオン変換

    return this;
}
```

#### makePerspective()（1118-1162行目）
```javascript
makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {
    const te = this.elements;

    const x = 2 * near / ( right - left );
    const y = 2 * near / ( top - bottom );

    const a = ( right + left ) / ( right - left );
    const b = ( top + bottom ) / ( top - bottom );

    let c, d;

    if ( coordinateSystem === WebGLCoordinateSystem ) {
        c = - ( far + near ) / ( far - near );
        d = ( - 2 * far * near ) / ( far - near );
    } else if ( coordinateSystem === WebGPUCoordinateSystem ) {
        c = - far / ( far - near );
        d = ( - far * near ) / ( far - near );
    }

    te[ 0 ] = x;  te[ 4 ] = 0;  te[ 8 ] = a;   te[ 12 ] = 0;
    te[ 1 ] = 0;  te[ 5 ] = y;  te[ 9 ] = b;   te[ 13 ] = 0;
    te[ 2 ] = 0;  te[ 6 ] = 0;  te[ 10 ] = c;  te[ 14 ] = d;
    te[ 3 ] = 0;  te[ 7 ] = 0;  te[ 11 ] = -1; te[ 15 ] = 0;

    return this;
}
```

### 4.3 プログラム呼び出し階層図
```
Matrix4
├── 基本操作
│   ├── set() / identity() / clone() / copy()
│   ├── copyPosition() / setFromMatrix3()
│   ├── extractBasis() / makeBasis()
│   └── extractRotation() / setPosition()
├── 行列演算
│   ├── multiply() → multiplyMatrices()
│   ├── premultiply() → multiplyMatrices()
│   ├── multiplyMatrices()
│   ├── multiplyScalar()
│   ├── determinant()
│   ├── invert()
│   └── transpose()
├── 変換行列生成
│   ├── makeTranslation()
│   ├── makeRotationX/Y/Z()
│   ├── makeRotationAxis()
│   ├── makeRotationFromEuler()
│   ├── makeRotationFromQuaternion() → compose()
│   ├── makeScale()
│   ├── makeShear()
│   └── lookAt()
├── 射影行列生成
│   ├── makePerspective()
│   └── makeOrthographic()
├── 合成・分解
│   ├── compose()
│   └── decompose()
└── その他
    ├── scale()
    ├── getMaxScaleOnAxis()
    ├── equals()
    ├── fromArray() / toArray()
```

### 4.4 関連ファイル一覧
| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| src/math/Matrix4.js | メイン | Matrix4クラスの実装 |
| src/math/Matrix3.js | 関連 | 3x3行列（抽出先） |
| src/math/Vector3.js | 関連 | 位置、スケール |
| src/math/Quaternion.js | 関連 | 回転表現 |
| src/math/Euler.js | 関連 | オイラー角 |
| src/core/Object3D.js | 利用者 | 変換行列の使用 |
| src/cameras/Camera.js | 利用者 | 射影行列の使用 |

## 5. 使用例

### 5.1 変換行列の合成
```javascript
const matrix = new THREE.Matrix4();
const position = new THREE.Vector3(10, 5, 0);
const quaternion = new THREE.Quaternion();
quaternion.setFromEuler(new THREE.Euler(0, Math.PI / 4, 0));
const scale = new THREE.Vector3(2, 2, 2);

matrix.compose(position, quaternion, scale);
```

### 5.2 変換行列の分解
```javascript
const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();

matrix.decompose(position, quaternion, scale);
console.log(position);  // (10, 5, 0)
console.log(scale);     // (2, 2, 2)
```

### 5.3 透視投影行列
```javascript
const camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
// 内部でmakePerspectiveが呼ばれる

// 手動での設定
const projMatrix = new THREE.Matrix4();
projMatrix.makePerspective(left, right, top, bottom, near, far);
```

### 5.4 lookAt行列
```javascript
const matrix = new THREE.Matrix4();
const eye = new THREE.Vector3(0, 0, 5);
const target = new THREE.Vector3(0, 0, 0);
const up = new THREE.Vector3(0, 1, 0);

matrix.lookAt(eye, target, up);
```

## 6. 備考

### 6.1 座標系の違い
- **WebGL**: Z深度範囲 [-1, 1]
- **WebGPU**: Z深度範囲 [0, 1]
- makePerspective()とmakeOrthographic()は座標系パラメータを受け取る

### 6.2 パフォーマンス考慮事項
- 行列乗算は比較的高コスト（64回の乗算、48回の加算）
- 可能な場合は事前計算してキャッシュ
- モジュールスコープの一時変数（_v1, _m1等）で再利用

### 6.3 decompose()の制限
非一様スケールの親を持つオブジェクトのワールド行列は、正確に分解できない場合がある。これはスキュー（せん断）成分が存在するため。

### 6.4 数学的背景
4x4変換行列の構造:
```
| R  R  R  Tx |   R: 回転・スケール（3x3）
| R  R  R  Ty |   T: 平行移動
| R  R  R  Tz |
| 0  0  0  1  |
```
この構造により、同次座標での変換が可能になる。
