# 画面設計書 29-CSS2Dサンプル

## 概要

本ドキュメントは、three.js Examples における CSS2D レンダラーを使用したサンプル（1件）の画面設計書である。3D オブジェクトに追従する 2D ラベルを DOM 要素で表示する CSS2DRenderer のデモンストレーションを提供する。

### 本画面の処理概要

CSS2Dサンプル画面は、three.js の CSS2DRenderer を使用して 3D オブジェクトにラベルを付けるサンプルを提供する。CSS2DObject は 3D シーン内の Object3D に追加され、その 3D 位置が 2D スクリーン座標に変換されて DOM 要素として表示される。テキストラベル、アノテーション、情報表示などに使用できる。

**業務上の目的・背景**：3D シーン内のオブジェクトに名前、説明、データ値などのテキスト情報を表示したい場合に、高品質なテキスト表示が可能。WebGL でテキストをレンダリングするよりも、CSS スタイリングが容易で、フォント表示がクリア。カメラレイヤー機能と組み合わせることで、表示/非表示の切り替えも可能。

**画面へのアクセス方法**：
1. examples/index.html にアクセス
2. 左側パネルの「css2d」カテゴリを選択
3. 「css2d_label」サンプルを選択

**主要な操作・処理内容**：
1. CSS2DRenderer の初期化と DOM への追加
2. CSS2DObject によるラベルの作成と 3D オブジェクトへの追加
3. camera.layers による表示/非表示制御
4. OrbitControls によるカメラ操作
5. GUI によるレイヤー切り替え

**画面遷移**：
- 遷移元：Examples一覧画面（examples/index.html）
- 遷移先：なし（各サンプルは独立して動作）
- GitHub ソースコードページへの外部リンクあり

**権限による表示制御**：なし（パブリックアクセス）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | Object3D | 主機能 | 2Dラベルの配置管理 |
| 19 | PerspectiveCamera | 補助機能 | カメラ設定 |
| 24 | Scene | 補助機能 | シーングラフ管理 |
| 13 | WebGLRenderer | 補助機能 | 3D レンダリング |

## 画面種別

サンプル / デモンストレーション

## URL/ルーティング

- カテゴリ: `examples/index.html` (css2d)
- サンプル: `examples/css2d_label.html`

## 入出力項目

| 項目名 | 入出力 | データ型 | 説明 |
|--------|--------|----------|------|
| ラベルテキスト | 入力 | String | 表示するテキスト内容 |
| レイヤー設定 | 入力 | Number | 表示するレイヤー番号 |
| GUI 操作 | 入力 | Event | レイヤー切り替え |
| 2D ラベル表示 | 出力 | DOM element | 3D 位置に追従するラベル |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| 3D シーン（地球と月） | Canvas (WebGL) | WebGLRenderer による 3D レンダリング |
| 2D ラベル | DOM div | CSS2DRenderer による 2D ラベル表示 |
| GUI パネル | DOM | レイヤー切り替えコントロール |

## イベント仕様

### 1-CSS2DRenderer 初期化

レンダラーの初期化と DOM への追加：
1. new CSS2DRenderer() でインスタンス作成
2. labelRenderer.setSize() でサイズ設定
3. labelRenderer.domElement.style.position = 'absolute'
4. document.body.appendChild(labelRenderer.domElement)

### 2-CSS2DObject 作成

ラベルを作成して 3D オブジェクトに追加：
1. div 要素を document.createElement('div') で作成
2. div.className = 'label' でスタイル適用
3. div.textContent = 'Earth' でテキスト設定
4. new CSS2DObject(div) でラップ
5. earthLabel.position.set(offset, 0, 0) でローカル位置設定
6. earth.add(earthLabel) で 3D オブジェクトに追加

### 3-レイヤーによる表示制御

カメラレイヤーを使用した表示/非表示：
1. camera.layers.enableAll() で全レイヤー表示
2. label.layers.set(0) でレイヤー0に名前ラベルを設定
3. label.layers.set(1) でレイヤー1に質量ラベルを設定
4. camera.layers.toggle(0) でレイヤー0の表示切り替え
5. camera.layers.toggle(1) でレイヤー1の表示切り替え

### 4-レンダリングループ

毎フレームの処理：
1. timer.update() で時間更新
2. moon.position を計算して更新
3. renderer.render(scene, camera) で WebGL レンダリング
4. labelRenderer.render(scene, camera) で CSS2D レンダリング

## データベース更新仕様

### 操作別データベース影響一覧

本画面はフロントエンドのみで動作するサンプルであり、データベースへのアクセスは行わない。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| - | - | - | データベース操作なし |

## メッセージ仕様

| 種別 | メッセージ | 発生条件 |
|------|-----------|----------|
| なし | - | CSS2DRenderer は特にメッセージを出力しない |

## 例外処理

| 例外状況 | 処理内容 |
|----------|----------|
| DOM 要素作成失敗 | 通常は発生しない |
| レイヤー設定不正 | 表示されないが、エラーは発生しない |

## 備考

- CSS2DRenderer と WebGLRenderer を同時に使用
- CSS2DRenderer の domElement は WebGLRenderer の上に重ねる
- ラベルの CSS スタイルは通常の CSS で設定可能
- camera.layers 機能で表示グループを制御可能
- CSS2DObject は常にカメラを向くビルボード効果がある

---

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

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

### 推奨読解順序

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

CSS2DRenderer と CSS2DObject の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CSS2DRenderer.js | `examples/jsm/renderers/CSS2DRenderer.js` | CSS2D レンダリングの実装 |

**読解のコツ**: CSS2DRenderer は CSS2DObject の 3D 位置をスクリーン座標に変換し、DOM 要素の left/top スタイルを設定する。CSS3DRenderer と異なり、回転やスケールは適用されず、常に正面を向く（ビルボード）。

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

css2d_label サンプルの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | css2d_label.html | `examples/css2d_label.html` | CSS2D ラベルサンプル |

**主要処理フロー**:
1. **Line 8-15**: ラベル用 CSS スタイル定義
2. **Line 31-36**: OrbitControls, CSS2DRenderer/CSS2DObject, GUI のインポート
3. **Line 42-66**: layers オブジェクトと camera.layers 操作関数
4. **Line 68-70**: Timer の初期化
5. **Line 77-193**: init() 関数
6. **Line 82-85**: camera の作成と layers.enableAll()
7. **Line 99-109**: 地球メッシュの作成
8. **Line 111-119**: 月メッシュの作成
9. **Line 123-135**: 地球ラベル（名前）を作成してレイヤー0に設定
10. **Line 137-146**: 地球ラベル（質量）を作成してレイヤー1に設定
11. **Line 148-168**: 月ラベル（名前と質量）を作成
12. **Line 172-181**: WebGLRenderer と CSS2DRenderer の初期化
13. **Line 183-185**: OrbitControls の設定
14. **Line 208-220**: animate() 関数で両レンダラーを render()

#### Step 3: レイヤー機能を理解する

camera.layers による表示制御を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | css2d_label.html | `examples/css2d_label.html` (Line 42-66, 225-236) | レイヤー設定 |

**主要処理フロー**:
- camera.layers.enableAll() で全レイヤー表示
- object.layers.set(n) でオブジェクトをレイヤー n に設定
- camera.layers.toggle(n) でレイヤー n の表示切り替え
- camera.layers.enable(n) / camera.layers.disable(n)

#### Step 4: 2つのレンダラーの連携を理解する

WebGLRenderer と CSS2DRenderer の同時使用を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | css2d_label.html | `examples/css2d_label.html` (Line 172-181, 218-219) | 2レンダラー連携 |

**主要処理フロー**:
- WebGLRenderer を先に作成して DOM に追加
- CSS2DRenderer を作成、position: absolute で重ねる
- OrbitControls は labelRenderer.domElement にバインド
- animate() で両方の render() を呼び出し

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

```
css2d_label.html (エントリーポイント)
    |
    +-- init()
    |      |
    |      +-- THREE.PerspectiveCamera()
    |      |      +-- camera.layers.enableAll()
    |      |
    |      +-- THREE.Scene()
    |      |
    |      +-- earth = new THREE.Mesh()
    |      |      +-- earth.layers.enableAll()
    |      |
    |      +-- earthLabel = new CSS2DObject(earthDiv)
    |      |      +-- earthLabel.layers.set(0)
    |      |      +-- earth.add(earthLabel)
    |      |
    |      +-- earthMassLabel = new CSS2DObject(earthMassDiv)
    |      |      +-- earthMassLabel.layers.set(1)
    |      |      +-- earth.add(earthMassLabel)
    |      |
    |      +-- [月についても同様]
    |      |
    |      +-- THREE.WebGLRenderer()
    |      |      +-- document.body.appendChild()
    |      |
    |      +-- CSS2DRenderer()
    |      |      +-- domElement.style.position = 'absolute'
    |      |      +-- document.body.appendChild()
    |      |
    |      +-- OrbitControls(camera, labelRenderer.domElement)
    |      |
    |      +-- initGui()
    |             +-- gui.add(layers, 'Toggle Name')
    |             +-- gui.add(layers, 'Toggle Mass')
    |
    +-- animate()
           +-- timer.update()
           +-- moon.position の更新
           +-- renderer.render(scene, camera)
           +-- labelRenderer.render(scene, camera)
```

### データフロー図

```
[CSS2D ラベルのデータフロー]

3D Object (earth/moon)
        |
        +-- CSS2DObject (earthLabel)
        |      |
        |      +-- div 要素 (textContent: "Earth")
        |      |
        |      +-- layers.set(0)
        |
        +-- CSS2DObject (earthMassLabel)
               |
               +-- div 要素 (textContent: "5.97237e24 kg")
               |
               +-- layers.set(1)

                              |
                              v
CSS2DRenderer.render(scene, camera)
        |
        +-- 3D 位置 → スクリーン座標変換
        |
        +-- div.style.left = screenX + 'px'
        |
        +-- div.style.top = screenY + 'px'
        |
        +-- camera.layers に基づいて表示/非表示
                              |
                              v
                        画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CSS2DRenderer.js | `examples/jsm/renderers/CSS2DRenderer.js` | ソース | CSS2D レンダラー |
| OrbitControls.js | `examples/jsm/controls/OrbitControls.js` | ソース | カメラコントロール |
| lil-gui.module.min.js | `examples/jsm/libs/lil-gui.module.min.js` | ソース | GUI ライブラリ |
| css2d_label.html | `examples/css2d_label.html` | テンプレート | ラベルサンプル |
| earth_atmos_2048.jpg | `examples/textures/planets/earth_atmos_2048.jpg` | リソース | 地球テクスチャ |
| moon_1024.jpg | `examples/textures/planets/moon_1024.jpg` | リソース | 月テクスチャ |
