シェーダー

シェーダーとは、3次元コンピュータグラフィックスにおいて、シェーディングを行うコンピュータプログラムのこと。「en」とは「次第に変化させる」「陰影・グラデーションを付ける」という意味で、「en」は頂点色やピクセル色などを次々に変化させるものを意味する。

1. 概要
-----

3DCGは様々な要素技術の集まりである。「物体」を三角形の集合で表現するモデリング、「動き」を計算するアニメーション・物理演算、「見た目」を生成するレンダリングなどである。その中でシェーダーはレンダリングの一部を担う。レンダリングは複数の段階からなるパイプラインで成っており、シェーダーはこのうちの「プログラム可能な部分」を意味する。例えば頂点シェーダーは頂点を入出力としてなんらかの処理を記述したものであり、例えばカメラを起点とする座標変換の記述に用いられる。

シェーダーはシェーディング言語を用いて記述される。頂点やピクセルが入出力に与えられ、座標変換/テクスチャマッピング/ライティングなどを含む任意の処理をプログラミングする。実行時には多くの場合シェーダープログラムはGPUへ引き渡され、頂点群やフラグメント群に対して並行的に呼び出されることで3DCGの「見た目」を生成する。

シェーダーはプログラムであるため、シェーディング言語と実行環境が許す任意の処理を記述できる。例えばピクセルシェーダーにおいて入力に含まれている色情報をすべて捨て去って真っ黒なピクセルを出力することも可能であるし、最新の研究に基づいた新しいライティングアルゴリズムを記述することもできる。シェーダーの用途によってシェーダーに記述される内容は異なり、これが3DCGの見た目の違いとなって現れる。

2. プロダクション用途のシェーダー
------------------

プロダクションレンダリングは、静止画あるいは動画の生成が最終目的であるが、動画の場合は複数枚の静止画をつなぎ合わせて最終的にコンポジットを行ない、動画を作り出す。

リアルタイム用途と比較すると、プロダクションレンダリングでは時間や資源の制約が少ない。例えば、映画作品の1シーンをレンダリングするために数時間から数日をかけ、高品質な映像を作り出してもかまわない。レンダリングのための膨大な一時情報がコンピュータの物理メモリに収まりきらない場合でも、ハードディスクなどの二次記憶領域に退避してレンダリングを続行することもできる。

プロダクション用途のシェーダーでは、時間はかかるが高品質でリアリティの高い結果を生成できる、レイトレーシングなどのより厳密な大域照明ベース・物理ベースの陰影計算モデルが用いられる。例えば、PIXARのRenderManはグローバルイルミネーションをサポートしている。

また、物体同士の相互反射光の計算や、ある物体から別の物体へ投影されるシャドウの計算は、シーン内のライトの数に比例して時間がかかるようになるが、プロダクションレンダリングではデザイナーの望む数だけ自由に光源を配置することができる。

3. リアルタイム用途のシェーダー
-----------------

ゲームなどのリアルタイムレンダリングでは、例えば60FPSの場合1フレームの描画にかけられる時間は最大でもわずか16ミリ秒程度であり、また頂点情報やテクスチャデータの格納・参照に使用できるビデオメモリの容量といった制約条件が多い。そのため、リアルタイム用途のシェーダーでは、相互反射などを考慮しない、低品質だが簡潔で高速な局所照明ベースの陰影計算モデルやZバッファ技法が用いられることが大多数である。GPUの進化とリアルタイム用プログラマブルシェーダーの発展を受けて、アルゴリズムやデータ構造を工夫してグローバルイルミネーションをリアルタイム実装している例も出てきているが、高性能なハードウェアを要求するなど、2018年時点でも未だ発展途上の技術である。シャドウや多光源環境のライティングに関しても、CSM/PSSMといった種々のシャドウマップ派生技術、および遅延シェーディング・遅延ライティングなどが考案されているが、時間および資源の制約が足かせとなり、品質や柔軟性はプロダクションレンダリングに及ばない。

リアルタイム用途のシェーダーはしばしばCGプロダクションソフトウェアのプレビューにも用いられる。最終出力に必要な高資源・高品質なレンダリングの代わりにリアルタイム用途のシェーダーを用いることで素早いプレビューが可能になる。例えばAutodesk 3ds Max、Autodesk Maya、Autodesk Softimage、およびNewTek LightWave 3Dはいずれもプログラマブルシェーダーによるプレビューを実装している。また2DCGソフトウェアにもアクセラレータとしてしばしば導入される。GUIベースオペレーティングシステム  のデスクトップ合成エンジンや標準2DグラフィックスAPIでも、Windows Aero/Direct2D  やQuartz Extreme/Core Image  などのように、GPUおよびプログラマブルシェーダーが活用される。

3.1. シェーダーステージ
--------------

多くのリアルタイム用途グラフィックスパイプラインは複数段のプログラマブルシェーダーと固定処理からなっている。プログラム可能な1つの段階はシェーダーステージと呼ばれる。以下は典型的なシェーダーステージである。

OpenGL 3.2以降とDirect3D 10以降では3種類のシェーダーを使用できる。

3.1.1. 頂点シェーダー
--------------

頂点シェーダーは主に入力頂点を座標変換するための機能である。頂点シェーダーはオブジェクトを構成する頂点の集合に対してのみ作用し、例えば3次元空間におけるXYZ位置座標や法線ベクトル、色、テクスチャマッピング座標といった頂点の属性だけを参照・変換できる。3次元グラフィックスにおける主な座標変換にはワールド変換、ビュー変換、プロジェクション変換、およびビューポート変換が存在するが、頂点シェーダーが担当するのはワールド・ビュー・プロジェクション変換である。ワールド・ビュー変換はモデル・ビュー変換とも呼ばれる。なお頂点単位のライティングであれば、頂点シェーダーで座標変換のほかにライティング計算を行なうこともできる。頂点シェーダーで計算された頂点情報はジオメトリシェーダーに渡されるか、そのままピクセルシェーダーに渡される。

Direct3D 9では頂点シェーダーをソフトウェアエミュレーションすなわちCPUで実行することもできるが、プログラマブルシェーダー機能に対応しているハードウェアであれば多数のプロセッサコアを使用して並列に処理を行なうことができるので、CPUで頂点シェーダーを実行するよりもGPUを利用した方が高速になる。

なお、シェーダーモデル3.0で導入されたVertex Texture Fetch  を使用すると、頂点シェーダーステージでテクスチャデータを参照することも可能となる。 シェーダーモデル4.0以降では、VTFはバッファデータの参照とともに標準化されている。 さらに、OpenGL 4.2ではすべてのシェーダーステージにおいてイメージオブジェクトに対するロード／ストアを可能にする機能が標準化された。DirectXにおいても、バージョン11.1にて、ピクセルシェーダーやコンピュートシェーダーだけでなく、すべてのシェーダーステージにおいて各種リソースに対する書き込みが可能になっている。

3.1.2. ジオメトリシェーダー
-----------------

ジオメトリシェーダーはピクセルシェーダーに渡されるオブジェクト内の頂点の集合を加工するために使用される。ジオメトリシェーダーにより、実行時に頂点数を増減させたり、プリミティブの種類を変更したりすることが可能となる。OpenGLではプリミティブシェーダーとも呼ばれる。

ジオメトリシェーダーはポイント、ライン、トライアングルといった既存のプリミティブから新しいプリミティブを生成できる。

ジオメトリシェーダーは頂点シェーダーの後に実行され、プリミティブ全体または隣接したプリミティブの情報を持つプリミティブを入力する。例えばトライアングルを処理するとき、3つの頂点がジオメトリシェーダーの入力となる。ジオメトリシェーダーはラスタライズされるプリミティブを出力でき、そのフラグメントは最終的にピクセルシェーダーに渡される。またプリミティブを出力せずにキャンセルすることもできる。

ジオメトリシェーダーのよくある使い方としては、ポイントスプライトの生成、ジオメトリテセレーション、シャドウボリュームの切り出し、キューブマップあるいはテクスチャ配列へのシングルパスレンダリングなどがある。

3.1.3. ピクセルシェーダー
----------------

ピクセルシェーダーはピクセル単位のライティングやポストプロセスを行なうための機能である。ピクセルシェーダーはラスタライズされるプリミティブの各ピクセルに影響する。また、ピクセルシェーダーにてテクスチャを参照することでバンプマッピングやフォグ、シャドウ、ブルームといったエフェクトを最終レンダリング結果に適用することもできる。OpenGLではフラグメントシェーダーと呼ばれる。

ピクセルシェーダーはピクセルを操作する機能であり、頂点シェーダーもしくはジオメトリシェーダーから入力された情報を元にテクスチャを合成したり表面色を適用したりする。ピクセルを操作する処理にかかる時間は入力プリミティブのラスタライズ後のピクセル数や出力解像度に左右されるため、通例は頂点単位の処理と比較して高負荷である。これをピクセルシェーダープログラムとしてプログラミングし、高い並列処理性能を持つGPUで実行することにより、バンプマッピング等のより高度なエフェクトをCPUですべて実行するよりもはるかに高いパフォーマンスで実現できる。なお、通常のレンダーターゲットを使ったピクセルシェーダーでは、アルファブレンド処理の詳細をプログラムすることはできない。

3.1.4. GPUパイプラインの概略
-------------------

Direct3D 9世代までのGPUでは、頂点シェーダーおよびピクセルシェーダーを担当するハードウェアユニットの数はそれぞれ製品ごとに固定されていたが、Direct3D 10世代の統合型シェーダーアーキテクチャでは各シェーダーユニットが統合され、複数の汎用シェーダーユニットを使って上記3つのシェーダーステージに動的に振り分ける形となる 。

これらのシェーダーはGPUのパイプライン内で実行される。下記はパイプライン内にどのように埋め込まれているのかを示す例である。

CPUは命令とジオメトリデータをGPU側に送信する。
頂点シェーダー内でジオメトリを変換し、頂点単位ライティングの計算などを実行する。
ジオメトリシェーダーを使用する場合は、頂点シェーダーが出力したジオメトリに対してプリミティブ増減や変更を行なう。
これまでの処理で計算されたジオメトリをトライアングルセットアップに設定する。トライアングルはquadに変換される。
ピクセルシェーダーを適用し、ピクセル単位ライティングなどを実行する。
視界判定を実行する。もし視界内にある場合はフレームバッファにピクセルを書き込む。頂点シェーダー／ジオメトリシェーダーの出力をラスタライザーおよびピクセルシェーダーに渡すのではなく、バッファやテクスチャなどのメモリリソースに書き出した後、インプットアセンブラーや頂点シェーダー／ジオメトリシェーダーに再入力する、ストリームアウトプットという機能も存在する。ストリームアウトプットはこれまでのようにGPU側でデータを参照するだけでなく、GPU自身が書き換えたデータを再利用することができるため、GPUパーティクルなどに応用できる。

3.1.5. テッセレーションシェーダー
--------------------

OpenGL 4.0以降とDirect3D 11以降ではさらにテッセレーションシェーダーをオプションとして使用できる。

3.2. 歴史
-------

RenderMan Shading Languageに代表されるように、プロダクション向けの3次元コンピュータグラフィックスのレンダリングでは古くからシェーディング処理をプログラムで記述してカスタマイズし、高品質な映像を作り出すといったことは当たり前のように行なわれてきた。一方でCADソフトやゲームなどのリアルタイム 2D/3Dグラフィックス アプリケーション開発者は、ソフトウェアによる定形の簡易シェーディングあるいはグラフィックスハードウェアに固定機能として実装されていた頂点変換・シェーディング機能すなわち「定形のパイプライン」を使用してグラフィック表示を行なっていた。

しかし、多数のグラフィック表現技術が次々と開発されていく中で、それらの技術をGPUメーカーが逐一ハードウェアに機能として実装していく形態は非効率であり、またユーザープログラマーが新しい技術を試すにはメーカーの対応を待たねばならなかった。この問題を解決するアイディアとして、GPUのパイプラインをソフトウェアプログラムにより組み立てる「プログラマブル パイプライン」と呼ばれるアーキテクチャが構築されることになる。以前は完全にブラックボックスだったグラフィックスパイプラインがユーザープログラマーに対して開放されることで、新たな陰影処理技法や各種エフェクトを試験的に実装してGPU上で走らせることが容易になり、先進的なGPUの機能を利用する優れた柔軟性と、表現力の爆発的な向上がもたらされた。

当時のOpenGL・DirectX  のAPIによってブラックボックスとして提供されていたシェーダーは固定機能シェーダーと呼ばれ、プログラマブルシェーダーと区別される。OpenGLにおいてはバージョン1.5からプログラマブルシェーダーが拡張として導入され、バージョン2.0からは標準化された。Direct3Dにおいてはバージョン8からプログラマブルシェーダーが導入された。OpenGL 3.1、OpenGL ES 2.0、およびDirect3D 10以降は固定機能シェーダーが廃止され、グラフィックスパイプラインはプログラマブルシェーダーによって記述される。現在ではリアルタイム処理系において「シェーダー」といえばプログラマブルシェーダーを指す 。また、Direct3D 9世代までは、頂点シェーダーとピクセルシェーダーの処理を担当するGPU内のハードウェア演算ユニットは完全に分かれており、それぞれの演算ユニットのことを「シェーダー」と呼んでいた。そのため、かつてはグラフィックスカードのハードウェア性能指標として演算ユニット数を表すために「シェーダー数」という言葉が使われていたが、統合型シェーダーアーキテクチャを採用したDirect3D 10世代以降は「ストリームプロセッサ数」あるいは「CUDAコア数」という言葉が用いられるようになっている 。

4. 並列処理
-------

シェーダーは膨大な要素の集合に対して変換処理を同時に適用するように記述される。例えばモデル内の全ての頂点を一様に平行移動・回転・拡大縮小したり、スクリーンの特定の範囲内の各ピクセルに対して一様にフィルタリング・輝度変換などを実行したりする、などである。これらの処理は対象となる全要素に等しく適用される。これは並列処理に非常に適しており、しばしばGPUを用いて処理される。例えばBlenderのCyclesエンジンやV-Ray RTはCUDAやOpenCLを経由してプロダクションレンダリングにGPUを活用する。

4.1. コンピュートシェーダー
----------------

GPGPU向けの汎用APIとして代表的なものはCUDAとOpenCLだが、OpenGL 4.3以降、OpenGL ES 3.1以降、およびDirect3D 11以降では、主にグラフィックス連携を重視したGPGPUのためのコンピュートシェーダーが搭載された。コンピュートシェーダーは前述のグラフィックスパイプラインとは独立して動作することのできるステージである。なお、コンピュートシェーダーは座標変換や陰影計算にとどまらない汎用計算が可能となっているため、「シェーダー」という命名はほかのシェーダーステージに合わせた便宜上のものである。Direct3Dのコンピュートシェーダーに関しては、Direct3D APIを含めた総称としてDirectComputeと呼ばれている。

コンピュートシェーダーがCUDAやOpenCLと比較して優れている点として、Direct3Dリアルタイムグラフィックスパイプラインとの連携がしやすい、Direct3D/HLSLをすでに利用している場合は修得が容易である、などが挙げられる。

5. シェーディング言語
------------

シェーダーを記述するための種々の言語がプロダクションレンダリング向けおよびリアルタイムレンダリング向けにそれぞれ開発されている。

多くの3DCGソフトウェアやオーサリングツール、ゲームエンジンにはノードエディタと呼ばれるGUIツールが搭載されており、ノードエディタを使うことでカスタムシェーダー開発を直感的に行なうことができるが、シェーディング言語を直接利用すると細やかな調整を行なうことができる。

6. 関連項目
-------

Direct3D
OpenGL
3次元コンピュータグラフィックス
シェーディング
レンダリング 
グラフィックスパイプライン
シェーディング言語
HLSL
GLSL
物理ベースシェーディング 
非写実的レンダリング 

7. 脚注
-----