# 通知設計書 44-NOTIFICATION_VISIBILITY_CHANGED (3D)

## 概要

本ドキュメントは、Godotエンジンにおける `NOTIFICATION_VISIBILITY_CHANGED` 通知（Node3D版）の設計仕様を記述する。この通知はNode3D通知の一種であり、3Dノードの可視性が変更された際に送信される。

### 本通知の処理概要

`NOTIFICATION_VISIBILITY_CHANGED` は、Node3Dおよびその派生クラスのノードの可視性（visible プロパティまたはis_visible_in_tree()の状態）が変更されたことを通知するためのシステム通知である。

**業務上の目的・背景**：3Dゲームやアプリケーションにおいて、オブジェクトの表示/非表示を切り替える際に、関連するリソースの最適化や処理の制御が必要になる。例えば、非表示になったオブジェクトのアニメーション停止、物理シミュレーションの一時停止、パーティクルエミッションの制御などが挙げられる。この通知により、可視性の変更を検知して適切な最適化処理を実行できる。また、LOD（Level of Detail）システムやカリング処理との連携にも使用される。

**通知の送信タイミング**：Node3Dのvisibleプロパティが変更された時、または親ノードの可視性変更により自身のis_visible_in_tree()状態が変化した時に送信される。具体的には、node_3d.cppの1084行目で`_propagate_visibility_changed()`メソッド内で`notification(NOTIFICATION_VISIBILITY_CHANGED)`が呼び出される。

**通知の受信者**：Node3Dクラスおよびそのすべての派生クラス（VisualInstance3D、CollisionObject3D、Light3D、CPUParticles3Dなど）。可視性が変更されたノードとその子孫すべてに伝播する。

**通知内容の概要**：整数値43（NOTIFICATION_VISIBILITY_CHANGED）が通知される。追加のパラメータは含まれない。

**期待されるアクション**：受信したノードは、可視性の変化に応じた処理を実行する。VisualInstance3Dではレンダリングインスタンスの表示/非表示を切り替え、CPUParticles3Dではエミッションの制御を行う。また、`visibility_changed`シグナルも発信されるため、スクリプトでシグナルハンドラを接続して処理することも可能。

## 通知種別

Godotエンジン内部通知（Node3D通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 通知値 | 43 |
| 送信方式 | 同期（notification呼び出し） |
| 伝播方向 | 親から子へ（下方向伝播） |
| 対象クラス | Node3Dおよびその派生クラス |

### 送信先決定ロジック

`_propagate_visibility_changed()`メソッドにより、可視性が変更されたノードとそのNode3D子孫すべてに伝播する。再帰的に子ノードの`_propagate_visibility_changed()`が呼び出される。

## 通知テンプレート

### 定数定義

| 項目 | 内容 |
|-----|------|
| 定義ファイル | scene/3d/node_3d.h |
| 定数名 | NOTIFICATION_VISIBILITY_CHANGED |
| 値 | 43 |

### 使用例

```gdscript
func _notification(what):
    if what == NOTIFICATION_VISIBILITY_CHANGED:
        # 可視性が変更された時の処理
        if is_visible_in_tree():
            _start_animations()
        else:
            _stop_animations()
```

```cpp
void Custom3DNode::_notification(int p_what) {
    switch (p_what) {
        case NOTIFICATION_VISIBILITY_CHANGED: {
            // 可視性が変更された時の処理
            _update_visibility();
        } break;
    }
}
```

### シグナル接続

```gdscript
# visibility_changedシグナルを使用する方法
func _ready():
    visibility_changed.connect(_on_visibility_changed)

func _on_visibility_changed():
    print("Visibility changed: ", is_visible_in_tree())
```

## テンプレート変数

この通知には追加のパラメータは含まれない。

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| p_what | 通知種別（43） | 直接渡される | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| プロパティ変更 | visibleの変更 | 自身のvisibleが変更された時 | set_visible()呼び出し時 |
| 親の可視性変更 | 親のvisible変更 | 親の可視性変更により自身の状態が変化した時 | 伝播により受信 |
| ツリー構造変更 | 親の変更 | 異なる可視性状態の親に移動した時 | reparent等で発生 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 状態変化なし | 実質的な可視性状態が変わらない場合は送信されない |
| ワールド外 | inside_world == false の場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[visible変更] --> B[set_visible呼び出し]
    B --> C{inside_world?}
    C -->|true| D[_propagate_visibility_changed]
    C -->|false| E[data.visible更新のみ]
    D --> F[notification<br/>VISIBILITY_CHANGED]
    F --> G[emit_signal<br/>visibility_changed]
    G --> H[ギズモ更新<br/>TOOLS_ENABLED]
    H --> I{子ノードあり?}
    I -->|Yes| J[子ノードへ伝播]
    I -->|No| K[終了]
    J --> D
```

## データベース参照・更新仕様

本通知はGodotエンジンの内部通知であり、データベースへのアクセスは行わない。

### 内部状態参照・更新

| 状態変数 | 操作 | 備考 |
|---------|------|------|
| data.visible | 参照/更新 | visibleプロパティの状態 |
| data.gizmos_dirty | 更新 | エディタでのギズモ更新フラグ |

### 派生クラスでの処理例

#### VisualInstance3D

| 処理 | 内容 |
|-----|------|
| インスタンス可視性更新 | _update_visibility()呼び出し |

#### CPUParticles3D

| 処理 | 内容 |
|-----|------|
| エミッション制御 | 可視性に応じてパーティクル処理を制御 |
| 内部状態更新 | _update_internal()呼び出し |

#### Light3D

| 処理 | 内容 |
|-----|------|
| ライト有効/無効 | RenderingServerへのライト状態更新 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 該当なし | - | この通知は単純な状態変更通知のためエラーケースなし |

## 配信設定

### プラットフォーム対応

| プラットフォーム | 対応状況 | 備考 |
|----------------|---------|------|
| 全プラットフォーム | 対応 | 3D機能を持つすべてのプラットフォーム |

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

本通知はエンジン内部の3Dノード可視性管理に使用されるものであり、セキュリティ上の特別な考慮事項はない。

## 備考

- `visibility_changed`シグナルが同時に発信される
- CanvasItem（2D）の同名通知とは別物（値が異なる）
- エディタ環境ではギズモの更新処理も実行される
- is_visible_in_tree()で現在の可視性状態を取得可能

---

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

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

### 推奨読解順序

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

まず、Node3Dクラスの通知定数定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | node_3d.h | `scene/3d/node_3d.h` | NOTIFICATION_VISIBILITY_CHANGED = 43 の定義を確認 |
| 1-2 | Node3D.xml | `doc/classes/Node3D.xml` | 385-388行目: 公式ドキュメントの記述を確認 |

**読解のコツ**: CanvasItem（2D）にも同名の通知があるが、値が異なることに注意。

#### Step 2: 送信メカニズムを理解する

処理の起点となる`_propagate_visibility_changed()`を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | node_3d.cpp | `scene/3d/node_3d.cpp` | _propagate_visibility_changed()の実装（1083-1103行目） |

**主要処理フロー**:
1. **1084行目**: `notification(NOTIFICATION_VISIBILITY_CHANGED)` の呼び出し
2. **1085行目**: `emit_signal(visibility_changed)` の呼び出し
3. **1087-1092行目**: エディタでのギズモ更新
4. **1094-1102行目**: 子ノードへの再帰的伝播

#### Step 3: 派生クラスでの処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | visual_instance_3d.cpp | `scene/3d/visual_instance_3d.cpp` | NOTIFICATION_VISIBILITY_CHANGEDでの_update_visibility()呼び出し（113-115行目） |
| 3-2 | cpu_particles_3d.cpp | `scene/3d/cpu_particles_3d.cpp` | パーティクルの可視性制御 |

**主要処理フロー**:
- **VisualInstance3D**: RenderingServerへのインスタンス可視性更新
- **CPUParticles3D**: エミッション状態の制御

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

```
Node3D::set_visible(bool)
    │
    └─ Node3D::_propagate_visibility_changed()
           │
           ├─ notification(NOTIFICATION_VISIBILITY_CHANGED)
           │      │
           │      └─ 派生クラス::_notification()
           │             └─ VisualInstance3D: _update_visibility()
           │             └─ CPUParticles3D: _update_internal()
           │
           ├─ emit_signal(visibility_changed)
           │
           ├─ _update_gizmos() [TOOLS_ENABLED]
           │
           └─ 子Node3D::_propagate_visibility_changed() [再帰]
```

### データフロー図

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

visible変更 ───▶ Node3D                      ───▶ 通知送信
                 ::set_visible()                   + シグナル発信
                        │
                        ▼
                 _propagate_visibility_changed()
                        │
                        ▼
                 notification() + emit_signal() ───▶ 派生クラス処理
                        │
                        ▼
                 子ノードへ再帰 ───▶ RenderingServerへの
                                       可視性更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| node_3d.h | `scene/3d/node_3d.h` | ヘッダー | NOTIFICATION_VISIBILITY_CHANGED定数定義 |
| node_3d.cpp | `scene/3d/node_3d.cpp` | ソース | _propagate_visibility_changed()（1083-1103行目） |
| visual_instance_3d.cpp | `scene/3d/visual_instance_3d.cpp` | ソース | 可視性更新処理（113-115行目） |
| cpu_particles_3d.cpp | `scene/3d/cpu_particles_3d.cpp` | ソース | パーティクル可視性制御 |
| light_3d.cpp | `scene/3d/light_3d.cpp` | ソース | ライト可視性制御 |
| Node3D.xml | `doc/classes/Node3D.xml` | ドキュメント | 通知の公式ドキュメント（385-388行目） |
