WebGL入門 その②（CG描画の仕組み、レンダリングパイプライン、GPU）

## はじめに

前回の記事では、WebGLの概要から開発環境の構築、そして基本的な三角形の描画までを解説しました。今回は、3Dグラフィックスがどのようにして画面に描画されるのか、その中心的な役割を担う**レンダリングパイプライン**について、初めて学ぶ人にも分かりやすく解説します。3D描画の全体像を理解するために、まずはCG描画の仕組みから、レンダリングパイプラインの各段階、そこで使われる行列、そしてGPUとの関係まで、体系的に見ていきましょう。

## 1. CG描画の仕組み：3Dから2Dへ

### 1-1. なぜレンダリングパイプラインが必要なのか？

私たちの世界は3次元（3D）で表現されますが、コンピュータの画面は2次元（2D）の平面です。3Dのオブジェクトを2Dの画面に表示するためには、**3D空間の情報を2Dの平面に変換する**というプロセスが必要になります。このプロセスがまさにレンダリングであり、その流れを効率的に行うための仕組みが**レンダリングパイプライン**です。

具体的には、以下のような課題を解決する必要があります。

*   **視点の問題**: 3D空間内のオブジェクトを、どの位置から、どの角度で見るのか（カメラの設定）を決定する必要があります。
*   **遠近感の問題**: 遠くのものが小さく見えるように、奥行きを考慮した投影を行う必要があります。
*   **隠面消去の問題**: 手前のオブジェクトが奥のオブジェクトを隠すように、見えない部分を適切に処理する必要があります。
*   **光源の問題**: オブジェクトに光を当て、影や反射を計算することで、立体感や質感を表現する必要があります。

### 1-2. レンダリングパイプラインの役割

レンダリングパイプラインは、これらの課題を解決するために、一連の処理を段階的に行います。各段階では、座標変換、クリッピング、ラスタライズ、シェーディングなどの処理が行われ、最終的にピクセル単位の色情報が決定されます。

レンダリングパイプラインは、**GPU（Graphics Processing Unit）上で実行されるように設計**されており、並列処理によって高速な描画を実現しています。

## 2. レンダリングパイプラインの各段階

レンダリングパイプラインは、大きく分けて以下の段階に分けられます。

```mermaid
---
config:
  theme: neutral
---
flowchart LR
    A["モデルデータ入力"] --> B("モデルビュー<br>変換")
    B --> C("射影変換")
    C --> D("クリッピング")
    D --> E("ビューポート変換")
    E --> F("ラスタライズ")
    F --> G("フラグメント<br>シェーディング")
    G --> H("Zテスト")
    H --> I("アルファ<br>ブレンディング")
    I --> J["画面出力"]
```

### 2-1. モデルデータ入力

レンダリングパイプラインの最初の段階では、3Dモデルのデータが入力されます。このデータには、以下のような情報が含まれます。

*   **頂点情報**: 3Dモデルの形状を構成する頂点の座標（x, y, z）。これらの頂点は、ローカル座標系で定義されていることが多いです。
*   **テクスチャ**: 3Dモデルの表面に貼り付ける画像。
*   **マテリアル**: 3Dモデルの表面の材質（色、光沢、反射率など）を定義する情報。

### 2-2. モデルビュー変換（Model-View Transformation）

モデルビュー変換では、3Dモデルを配置し、視点を設定します。具体的には、以下の2つの変換を組み合わせます。

*   **モデル変換（Model Transformation）**: 3Dモデルをワールド座標系（シーン全体の座標系）に配置します。ローカル座標系からワールド座標系への変換を行います。拡大縮小、回転、平行移動などの操作を組み合わせて適用します。
*   **ビュー変換（View Transformation）**: カメラの位置と向きを設定し、ワールド座標系をカメラの視点から見たビュー座標系に変換します。ワールド座標系を基準としたカメラの位置と向きの情報を基に、シーン全体をカメラから見た状態に変換します。

![Modeling_transformation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34853/24d5d9c3-bb78-46f0-b2f6-76d3e0956a51.png)

### 2-3. 射影変換（Projection Transformation）

射影変換では、ビュー座標系で表現された3Dモデルを2Dの画面に投影します。遠近感を表現するために、透視投影（Perspective Projection）または正射影（Orthographic Projection）を使用します。この変換により、3D空間の情報を2Dの平面に写像します。

*   **透視投影**: 遠くのものが小さく見えるように、奥行きを考慮した投影を行います。人間の視覚に近い表現が可能です。
*   **正射影**: 奥行きに関係なく、同じ大きさで投影されます。建築設計図やCADなどでよく使用され、正確な寸法を保つことが重要な場合に使用されます。

![Viewing_transformation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34853/36b42cfb-eb28-4f24-838a-2a46ccb8f91c.png)

### 2-4. クリッピング（Clipping）

クリッピングでは、画面外にあるオブジェクト、または視錐台（カメラから見える範囲）から外れたオブジェクトを削除します。これにより、描画する必要のない部分を省き、無駄な処理を削減することで、レンダリングの効率を高めます。クリッピングは、パフォーマンス向上に不可欠な処理です。

![Clipping.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34853/897bc6ef-f380-4db7-85e9-e50fb539d344.png)

### 2-5. ビューポート変換（Viewport Transformation）

ビューポート変換では、クリッピング処理後の3Dモデルを、実際の画面のピクセル座標に変換します。正規化デバイス座標系（NDC）からウィンドウ座標系への変換を行います。NDCは-1から1の範囲で定義された座標系ですが、ウィンドウ座標系は実際の画面の解像度に対応したピクセル単位の座標系です。

![Device axis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34853/0602c52a-226f-4d77-a7c8-b09b228253ad.png)

### 2-6. ラスタライズ（Rasterization）

ラスタライズでは、3Dモデルを構成するポリゴン（通常は三角形）を、ピクセル単位に分解します。ポリゴンの内部にあるピクセルを特定し、それぞれのピクセルの座標を計算します。この段階で、ポリゴンがピクセルに変換され、描画の準備が整います。


### 2-7. フラグメントシェーディング（Fragment Shading）

フラグメントシェーディングでは、ラスタライズされたピクセル（フラグメント）の色を計算します。シェーダプログラム（フラグメントシェーダ）を使用して、光の当たり方、テクスチャ、影などを計算し、最終的なピクセルの色を決定します。この段階で、表面の材質や光源の影響が考慮され、リアルな表現が実現されます。

![Rasterization_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34853/03fc028a-03b0-43f6-99c5-ec9dcfccbf15.png)

### 2-8. Zテスト（Depth Testing）

Zテストでは、ピクセルごとの奥行き情報を比較し、手前のピクセルのみを描画します。Zバッファを使用して、手前のオブジェクトが奥のオブジェクトを隠すという、3D空間における自然な描画を実現します。これにより、隠面消去が行われ、正しい奥行き関係が保たれます。

### 2-9. アルファブレンディング（Alpha Blending）

アルファブレンディングでは、透過（Alpha）情報を考慮して、ピクセルを合成します。半透明のオブジェクトを重ねて描画する際に、背景の色とオブジェクトの色を合成し、正しい透明度を表現します。透過処理を行うことで、ガラスや煙などの表現が可能になります。

## 3. 各変換における行列の役割

レンダリングパイプラインにおける座標変換は、**行列（Matrix）** と呼ばれる数値の配列を使って表現されます。行列を使用することで、複数の変換をまとめて表現したり、逆変換を簡単に計算したりすることができます。

### 3-1. 行列とは？

行列は、数値を縦横に並べたものです。3Dグラフィックスでは、主に4x4の行列が使用されます。行列は、頂点の座標を変換したり、オブジェクトを回転させたり、拡大縮小したりするために使用されます。

### 3-2. 各変換行列の種類

*   **モデル行列（Model Matrix）**: モデルをワールド座標系に配置するための変換行列です。拡大縮小、回転、平行移動などの変換を組み合わせたものです。ローカル座標系からワールド座標系への変換を行います。
*   **ビュー行列（View Matrix）**: カメラの位置と向きを定義するための変換行列です。ワールド座標系をビュー座標系に変換します。カメラの位置と向きを基に、シーン全体をカメラから見た状態に変換します。
*   **射影行列（Projection Matrix）**: ビュー座標系をクリップ座標系に変換するための変換行列です。透視投影または正射影を定義します。3D空間の情報を2Dの平面に投影します。

### 3-3. 行列の組み合わせ

これらの行列を組み合わせることで、3Dモデルを画面に表示するための一連の変換を効率的に行うことができます。例えば、モデルビュー射影行列（Model-View-Projection Matrix: MVP行列）は、モデル行列、ビュー行列、射影行列を掛け合わせたもので、1つの行列で3Dモデルを画面に投影することができます。これにより、複数の変換をまとめてGPUに送ることができ、処理効率が向上します。

## 4. レンダリングパイプラインとGPUの関係

### 4-1. GPU（Graphics Processing Unit）とは？

GPU（Graphics Processing Unit）は、画像処理に特化したプロセッサです。CPUが汎用的な処理を行うのに対し、GPUは3Dグラフィックスの計算、テクスチャの処理、シェーディングなど、並列処理が必要なタスクを高速に処理するのに適しています。GPUは、大量のデータを同時に処理する能力に優れており、リアルタイムな3Dグラフィックスの描画に不可欠な存在です。

### 4-2. レンダリングパイプラインとGPUの関係

レンダリングパイプラインは、GPU上で実行されるように設計されています。**GPUは、多数の小さなコアを持ち、SIMD（Single Instruction, Multiple Data）アーキテクチャに基づいて並列処理を行います。** これにより、大量の頂点やピクセルに対して同じ処理を同時に行うことができ、3Dグラフィックスの描画を高速化することができます。レンダリングパイプラインの各段階は、GPUの機能を最大限に活用するように最適化されています。

### 4-3. シェーダプログラム

レンダリングパイプラインの一部の段階（頂点シェーディング、フラグメントシェーディング）では、**シェーダプログラムと呼ばれるプログラムがGPU上で実行されます。** シェーダプログラムは、C言語に似たGLSL（OpenGL Shading Language）で記述され、頂点の座標変換やピクセルの色計算などの処理を行います。これらの処理をGPUに任せることで、CPUの負荷を軽減し、より複雑な3Dグラフィックスをリアルタイムに描画することができます。シェーダプログラムは、開発者がGPUの機能をカスタマイズするための重要な手段です。

### 4-4. WebGLとGPU

WebGLは、ウェブブラウザ上でGPUを利用するためのAPIです。WebGLを使用することで、JavaScriptからシェーダプログラムを実行し、3Dグラフィックスを描画することができます。WebGLは、GPUの機能を直接利用することで、ウェブブラウザ上でネイティブアプリケーションに匹敵する高性能な3Dグラフィックスを実現します。WebGLは、クロスプラットフォームな3Dグラフィックス開発を可能にする強力なツールです。

## まとめ

今回は、CG描画の仕組みから、レンダリングパイプラインの各段階、そこで使われる行列、そしてGPUとの関係まで、体系的に解説しました。レンダリングパイプラインは、3Dグラフィックスの描画において中心的な役割を担う重要な概念です。今回の記事を参考に、WebGLでの3Dグラフィックスプログラミングに挑戦してみてください。