# 機能設計書 168-PMREMGenerator

## 概要

本ドキュメントは、Three.jsライブラリにおけるPMREMGenerator機能の設計仕様を記述する。PMREMGeneratorは、環境マップをPBR（物理ベースレンダリング）用に事前フィルタリングし、様々なラフネスレベルでのIBL（Image-Based Lighting）を実現するためのクラスである。

### 本機能の処理概要

PMREMGenerator（Prefiltered Mipmapped Radiance Environment Map Generator）は、キューブマップまたはEquirectangular形式の環境テクスチャを入力として、マテリアルのラフネスに応じた異なるぼかしレベルを持つミップマップを生成する。GGX VNDF（Visible Normal Distribution Function）重要度サンプリングを使用して、物理的に正確な環境マップフィルタリングを行う。

**業務上の目的・背景**：PBRマテリアルは、環境光をリアルに反映するためにラフネスに応じた異なるぼかしレベルの環境マップを必要とする。光沢のある表面は鮮明な反射を、粗い表面はぼやけた反射を示す。PMREMGeneratorは、単一の環境マップからこれらの異なるレベルを事前計算することで、リアルタイムレンダリングの品質とパフォーマンスを両立させる。

**機能の利用シーン**：
- HDR環境マップの読み込み時の前処理
- PBRマテリアルの環境反射設定
- スカイボックスからの環境光生成
- シーンからの動的環境マップ生成

**主要な処理内容**：
1. fromScene() - シーンからPMREMを生成
2. fromEquirectangular() - Equirectangular画像からPMREMを生成
3. fromCubemap() - キューブマップからPMREMを生成
4. GGX VNDFフィルタリング - 物理ベースのぼかし処理
5. CubeUVフォーマット - 特殊なUV配置での出力

**関連システム・外部連携**：WebGLRenderer、MeshStandardMaterial、MeshPhysicalMaterial、環境マップと連携。

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | Viewport | 補助機能 | 環境マップのPBR用フィルタリング |

## 機能種別

計算処理 / GPU処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| renderer | WebGLRenderer | Yes | レンダラーインスタンス | 有効なレンダラー |
| scene | Scene | Yes | キャプチャ対象シーン（fromScene用） | 有効なシーン |
| sigma | number | No | ブラー半径（ラジアン、デフォルト: 0） | 0以上 |
| near | number | No | 近クリップ面（デフォルト: 0.1） | 正の数値 |
| far | number | No | 遠クリップ面（デフォルト: 100） | 正の数値 |
| options.size | number | No | テクスチャサイズ（デフォルト: 256） | 2の累乗 |
| options.position | Vector3 | No | キューブカメラ位置（デフォルト: 原点） | 有効なベクトル |
| equirectangular | Texture | Yes | Equirectangularテクスチャ（fromEquirectangular用） | 有効なテクスチャ |
| cubemap | CubeTexture | Yes | キューブマップ（fromCubemap用） | 有効なキューブテクスチャ |

### 入力データソース

環境マップテクスチャ（HDR、LDR）、またはシーンオブジェクト。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| renderTarget | WebGLRenderTarget | PMREM付きレンダーターゲット |
| texture | Texture | CubeUVフォーマットのテクスチャ |

### 出力先

レンダーターゲットとして返却。scene.environmentやmaterial.envMapに設定可能。

## 処理フロー

### 処理シーケンス

```
1. PMREMGeneratorインスタンス生成
   └─ rendererへの参照を保存
2. fromScene/fromEquirectangular/fromCubemap呼び出し
   └─ レンダーターゲットを確保
   └─ 入力テクスチャをCubeUV形式に変換
   └─ 各LODレベルでGGXフィルタリング
   └─ 結果をレンダーターゲットに出力
3. 結果の利用
   └─ scene.environment = target.texture
4. dispose()
   └─ 内部リソースを解放
```

### フローチャート

```mermaid
flowchart TD
    A[PMREMGenerator生成] --> B{入力ソース?}
    B -->|Scene| C[fromScene]
    B -->|Equirectangular| D[fromEquirectangular]
    B -->|Cubemap| E[fromCubemap]
    C --> F[6方向レンダリング]
    D --> G[テクスチャ変換]
    E --> G
    F --> H[CubeUV変換]
    G --> H
    H --> I[LOD 0 生成]
    I --> J[GGX VNDF フィルタリング]
    J --> K[LOD 1-N 生成]
    K --> L{全LOD完了?}
    L -->|No| J
    L -->|Yes| M[レンダーターゲット返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | LOD_MIN | 最小LODレベルは4（16x16ピクセル） | 常時 |
| BR-002 | GGXサンプル数 | 256サンプルで重要度サンプリング | GGXフィルタリング時 |
| BR-003 | インクリメンタルラフネス | 各LODで差分ラフネスを適用 | LOD生成時 |
| BR-004 | CubeUVフォーマット | 特殊なUV配置でミップマップを格納 | 常時 |

### 計算ロジック

**GGX VNDF重要度サンプリング**: Heitz (2018) の手法に基づき、視認可能な法線分布関数に従ってサンプルを生成。`incrementalRoughness = sqrt(targetRoughness^2 - sourceRoughness^2)`で差分ラフネスを計算。

## データベース操作仕様

該当なし（クライアントサイドのGPU処理）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Warning | sigmaRadiansが大きすぎる | サンプル数を制限（MAX_SAMPLES=20） |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- fromScene()はシーンを6方向レンダリングするため比較的高コスト
- fromEquirectangular()、fromCubemap()はテクスチャ変換のみで高速
- シェーダーコンパイルは初回のみ発生（compileCubemapShader/compileEquirectangularShaderで事前コンパイル可能）

## セキュリティ考慮事項

特になし

## 備考

- 推奨入力サイズ: Equirectangular 1024x512、Cubemap 256x256
- HalfFloatTypeで出力し、HDRをサポート
- dispose()でGPUリソースを適切に解放すること

---

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

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

PMREMGeneratorはレンダラーへの参照と内部シェーダーマテリアルを保持する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | クラス定義と定数（27-92行目） |

**読解のコツ**: LOD_MIN=4がミップマップの最小サイズを決定。GGX_SAMPLES=256が品質を決定。EXTRA_LOD_SIGMAは追加のぼかしレベルを定義。

#### Step 2: パブリックAPIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | fromScene (109-141行目) |
| 2-2 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | fromEquirectangular (152-156行目) |
| 2-3 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | fromCubemap (167-171行目) |

**主要処理フロー**:
1. **116-119行目**: 現在のレンダー状態を保存
2. **125行目**: _allocateTargets()でレンダーターゲット確保
3. **128行目**: _sceneToCubeUV()でシーンを6方向レンダリング
4. **130-134行目**: sigma > 0の場合ブラー適用
5. **136行目**: _applyPMREM()でGGXフィルタリング

#### Step 3: 内部処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | _allocateTargets (286-323行目) |
| 3-2 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | _applyPMREM (488-505行目) |
| 3-3 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | _applyGGXFilter (518-561行目) |

**主要処理フロー**:
- **288-289行目**: ターゲットサイズ計算（3 * max(cubeSize, 112) x 4 * cubeSize）
- **301行目**: HalfFloatTypeでレンダーターゲット作成
- **497-501行目**: 各LODレベルでGGXフィルタ適用
- **530-536行目**: インクリメンタルラフネス計算

#### Step 4: シェーダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | _getGGXShader (790-925行目) |
| 4-2 | PMREMGenerator.js | `src/extras/PMREMGenerator.js` | GGX VNDF実装（843-865行目のGLSL） |

**主要処理フロー**:
- **828-840行目**: Hammersley配列でサンプル点生成
- **845-865行目**: GGX VNDF重要度サンプリング（Heitz 2018）
- **885-907行目**: モンテカルロ積分でプリフィルタリング

### プログラム呼び出し階層図

```
PMREMGenerator
    │
    ├─ fromScene(scene, sigma, near, far, options)
    │      ├─ _setSize(size)
    │      ├─ _allocateTargets()
    │      ├─ _sceneToCubeUV() - 6方向レンダリング
    │      ├─ [Optional] _blur() - sigmaブラー
    │      ├─ _applyPMREM()
    │      │     └─ _applyGGXFilter() [LOD繰り返し]
    │      └─ _cleanup()
    │
    ├─ fromEquirectangular(texture)
    │      └─ _fromTexture()
    │             ├─ _allocateTargets()
    │             ├─ _textureToCubeUV()
    │             ├─ _applyPMREM()
    │             └─ _cleanup()
    │
    ├─ fromCubemap(cubemap)
    │      └─ _fromTexture() [同上]
    │
    └─ dispose()
           ├─ _dispose() - 内部リソース解放
           ├─ _cubemapMaterial.dispose()
           └─ _equirectMaterial.dispose()
```

### データフロー図

```
[入力]                    [処理]                         [出力]

Scene ─────────────────▶ fromScene() ──────────────────▶ WebGLRenderTarget
                           ├─ 6方向レンダリング              (CubeUV形式)
                           └─ GGXフィルタリング

Equirectangular ───────▶ fromEquirectangular() ────────▶ WebGLRenderTarget
                           ├─ UV変換                        (CubeUV形式)
                           └─ GGXフィルタリング

CubeMap ───────────────▶ fromCubemap() ────────────────▶ WebGLRenderTarget
                           ├─ キューブ変換                   (CubeUV形式)
                           └─ GGXフィルタリング
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PMREMGenerator.js | `src/extras/PMREMGenerator.js` | ソース | 本機能のメイン実装 |
| WebGLRenderTarget.js | `src/renderers/WebGLRenderTarget.js` | ソース | 出力ターゲット |
| ShaderMaterial.js | `src/materials/ShaderMaterial.js` | ソース | カスタムシェーダー |
| OrthographicCamera.js | `src/cameras/OrthographicCamera.js` | ソース | フラットカメラ |
| PerspectiveCamera.js | `src/cameras/PerspectiveCamera.js` | ソース | キューブカメラ |
| BufferGeometry.js | `src/core/BufferGeometry.js` | ソース | LODメッシュ |
| Mesh.js | `src/objects/Mesh.js` | ソース | レンダリングメッシュ |
| MeshBasicMaterial.js | `src/materials/MeshBasicMaterial.js` | ソース | 背景描画用 |
| BoxGeometry.js | `src/geometries/BoxGeometry.js` | ソース | 背景ボックス |
