# 機能設計書 19-PerspectiveCamera

## 概要

本ドキュメントは、Three.jsライブラリにおけるPerspectiveCamera機能の設計を詳細に記述するものである。PerspectiveCameraは、透視投影を使用して3Dシーンを描画するための標準的なカメラクラスである。

### 本機能の処理概要

PerspectiveCameraクラスは、人間の目が見る方法を模倣した透視投影を提供する。遠くのオブジェクトは小さく、近くのオブジェクトは大きく表示され、3Dシーンに奥行き感を与える。FOV（視野角）、アスペクト比、ニアプレーン、ファープレーンによって視錐台を定義する。

**業務上の目的・背景**：3Dグラフィックスにおいて、透視投影は最も一般的に使用される投影方法である。現実世界で人間が物を見る方法に近い表現が可能であり、ゲーム、建築ビジュアライゼーション、映画制作など、ほとんどの3Dアプリケーションで使用される。PerspectiveCameraは、この透視投影を簡単に設定・制御するためのクラスである。

**機能の利用シーン**：3Dゲーム、3Dエディタ、建築ビジュアライゼーション、製品コンフィギュレータ、VR/ARアプリケーション、映画的なカメラワークなど。

**主要な処理内容**：
1. 視野角（FOV）に基づくプロジェクション行列の計算
2. アスペクト比の管理とリサイズ対応
3. ニア/ファークリッピングプレーンの設定
4. 焦点距離とフィルムゲージによるFOV計算
5. ビューオフセット（マルチモニター対応）
6. ズーム機能

**関連システム・外部連携**：Camera（継承元）、Matrix4（プロジェクション行列）、StereoCamera（VR用）。

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | エディタメイン画面 | 主機能 | 3Dビューのカメラ制御 |
| 2 | Viewport | 主機能 | Viewportカメラの透視投影 |
| 12 | Menubar - Add | 補助機能 | 透視投影カメラの追加 |

## 機能種別

3Dオブジェクト / カメラ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fov | number | No | 垂直視野角（度） | デフォルト: 50 |
| aspect | number | No | アスペクト比 | デフォルト: 1 |
| near | number | No | ニアクリッピングプレーン | デフォルト: 0.1, >0 |
| far | number | No | ファークリッピングプレーン | デフォルト: 2000 |

### 入力データソース

- コンストラクタパラメータ
- setFocalLength()による焦点距離

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| projectionMatrix | Matrix4 | 透視プロジェクション行列 |
| projectionMatrixInverse | Matrix4 | プロジェクション行列の逆行列 |
| fov | number | 現在の視野角 |
| aspect | number | 現在のアスペクト比 |

### 出力先

- レンダラーに渡されてシェーダーで使用

## 処理フロー

### 処理シーケンス

```
1. PerspectiveCameraインスタンスの生成
   └─ Camera初期化、パラメータ設定、updateProjectionMatrix()

2. パラメータ変更時
   ├─ fov, aspect, near, far等を変更
   └─ updateProjectionMatrix()を手動呼び出し

3. リサイズ対応
   ├─ aspect = canvas.width / canvas.height
   └─ updateProjectionMatrix()

4. updateProjectionMatrix()内部
   ├─ 視錐台パラメータ計算（top, height, width, left）
   ├─ ビューオフセット適用（マルチモニター用）
   ├─ フィルムオフセット適用
   └─ projectionMatrix.makePerspective()

5. レンダリング時
   └─ レンダラーがprojectionMatrixを使用
```

### フローチャート

```mermaid
flowchart TD
    A[PerspectiveCamera生成] --> B[Camera基底クラス初期化]
    B --> C[fov, aspect, near, far設定]
    C --> D[updateProjectionMatrix]
    D --> E[top = near * tan(fov/2) / zoom]
    E --> F[height = 2 * top]
    F --> G[width = aspect * height]
    G --> H{view設定あり?}
    H -->|Yes| I[ビューオフセット適用]
    H -->|No| J{filmOffset != 0?}
    I --> J
    J -->|Yes| K[フィルムオフセット適用]
    J -->|No| L[projectionMatrix.makePerspective]
    K --> L
    L --> M[projectionMatrixInverse.invert]
    M --> N[レンダリング準備完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | Camera継承 | Cameraクラスを継承 | クラス定義 |
| BR-02 | タイプフラグ | isPerspectiveCamera=trueを設定 | インスタンス生成時 |
| BR-03 | 初期FOV | fovのデフォルトは50度 | パラメータ未指定時 |
| BR-04 | ニア制約 | nearは0より大きい必要あり | 透視投影の性質 |
| BR-05 | 手動更新 | プロパティ変更後はupdateProjectionMatrix()が必要 | パラメータ変更時 |
| BR-06 | ズーム適用 | FOVはzoom値で除算される | プロジェクション計算時 |

### 計算ロジック

- top = near * tan(fov/2 * DEG2RAD) / zoom
- height = 2 * top
- width = aspect * height
- fov = 2 * atan(filmHeight/2 / focalLength) * RAD2DEG（setFocalLength時）

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 数学エラー | near <= 0 | nearは正の値を設定 |
| - | 視覚問題 | near/far比が大きすぎる | 適切な範囲に設定 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- updateProjectionMatrix()は必要時のみ呼び出し
- フレームごとの不要な再計算を避ける

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

該当なし

## 備考

- setViewOffset()でマルチモニター対応可能
- filmGauge/filmOffsetで映画撮影的なFOV制御が可能
- focus値はStereoCamera/DOF用

---

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

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

### 推奨読解順序

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

PerspectiveCameraの構造とその依存関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PerspectiveCamera.js | `src/cameras/PerspectiveCamera.js` | クラス定義全体 |
| 1-2 | Camera.js | `src/cameras/Camera.js` | 継承元クラス |
| 1-3 | MathUtils.js | `src/math/MathUtils.js` | DEG2RAD, RAD2DEG定数 |

**読解のコツ**: PerspectiveCameraはCameraを継承し、FOV、アスペクト比、ニア/ファープレーンでプロジェクション行列を計算する。updateProjectionMatrix()が中核メソッド。

#### Step 2: エントリーポイントを理解する

PerspectiveCameraの初期化と主要メソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PerspectiveCamera.js | `src/cameras/PerspectiveCamera.js` | コンストラクタ・メソッド |

**主要処理フロー**:
1. **33行目**: コンストラクタでfov, aspect, near, farを受け取る
2. **44行目**: isPerspectiveCameraフラグをtrueに設定
3. **46行目**: type = 'PerspectiveCamera'
4. **55行目**: fovプロパティ（デフォルト50）
5. **63行目**: zoomプロパティ（デフォルト1）
6. **75行目**: nearプロパティ（デフォルト0.1）
7. **84行目**: farプロパティ（デフォルト2000）
8. **94行目**: focusプロパティ（デフォルト10）
9. **102行目**: aspectプロパティ（デフォルト1）
10. **111行目**: viewプロパティ（nullまたはオブジェクト）
11. **121行目**: filmGaugeプロパティ（デフォルト35mm）
12. **129行目**: filmOffsetプロパティ（デフォルト0）
13. **131行目**: コンストラクタ最後にupdateProjectionMatrix()呼び出し
14. **164-172行目**: setFocalLength() - 焦点距離からFOVを計算
15. **180-186行目**: getFocalLength() - FOVから焦点距離を計算
16. **304-332行目**: setViewOffset() - マルチモニター対応
17. **353-381行目**: updateProjectionMatrix() - 核心メソッド

#### Step 3: updateProjectionMatrixを詳細に理解する

プロジェクション行列計算の詳細を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PerspectiveCamera.js | `src/cameras/PerspectiveCamera.js` | updateProjectionMatrix内部 |

**主要処理フロー**:
1. **355行目**: near取得
2. **356行目**: top = near * tan(fov/2) / zoom
3. **357行目**: height = 2 * top
4. **358行目**: width = aspect * height
5. **359行目**: left = -0.5 * width
6. **360行目**: view取得
7. **362-372行目**: view.enabled時のオフセット適用
8. **374-375行目**: filmOffset適用
9. **377行目**: projectionMatrix.makePerspective()呼び出し
10. **379行目**: projectionMatrixInverse計算

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

```
PerspectiveCamera
    │
    └─ extends Camera
            │
            └─ extends Object3D

PerspectiveCamera.updateProjectionMatrix()
    │
    ├─ top = near * tan(fov/2) / zoom
    │
    ├─ height = 2 * top
    │
    ├─ width = aspect * height
    │
    ├─ left = -0.5 * width
    │
    ├─ [view offset適用]
    │
    ├─ [filmOffset適用]
    │
    ├─ projectionMatrix.makePerspective(left, right, top, bottom, near, far)
    │
    └─ projectionMatrixInverse.invert()
```

### データフロー図

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

fov, aspect, near, far
    │
    ▼
PerspectiveCamera() ─────────────▶ 初期パラメータ設定 ────────────▶ プロパティ設定
    │
    ▼
updateProjectionMatrix() ────────▶ 視錐台計算 ────────────────────▶ projectionMatrix
    │                                   │
    │                                   ▼
    │                            Matrix4.makePerspective()
    │
    ▼
setFocalLength(mm) ──────────────▶ fov計算 ────────────────────────▶ fov更新
    2 * atan(filmHeight/2 / focalLength)
    │
    ▼
setViewOffset() ─────────────────▶ view設定 ───────────────────────▶ マルチモニター対応
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PerspectiveCamera.js | `src/cameras/PerspectiveCamera.js` | ソース | 透視投影カメラ |
| Camera.js | `src/cameras/Camera.js` | ソース | 基底カメラクラス |
| Object3D.js | `src/core/Object3D.js` | ソース | 3Dオブジェクト基底 |
| Matrix4.js | `src/math/Matrix4.js` | ソース | 行列クラス（makePerspective） |
| MathUtils.js | `src/math/MathUtils.js` | ソース | DEG2RAD, RAD2DEG |
| Vector2.js | `src/math/Vector2.js` | ソース | getViewBounds用 |
| Vector3.js | `src/math/Vector3.js` | ソース | 内部計算用 |
| StereoCamera.js | `src/cameras/StereoCamera.js` | ソース | VR用派生クラス |
