説明しよう!シェーダーとはッ!

=前置きの前置き=

 3.11からしばらくの間は個人開発する意欲がなくて、文章ネタを書いてる方が気楽な時期があった。

 というわけで、その頃に書いた「昔の自分が知りたかった」ネタを載せてみる。

=前置き=

 2次元のゲームでは必要ないのに、3次元のゲームでは必要になる概念。それがシェーダーである。


 シェーダーは大まかに言って「頂点シェーダー」と「ピクセルシェーダー」がある。なんで2つもあるんだろうか。なんで1つにまとめないのか。そもそもシェーダーって何だ。それらを理解するためには「3次元描画の流れ」を知る必要がある。


 ということで、以下では「3次元描画の流れ」を説明しつつ、シェーダーの役割について解説する。

=頂点シェーダー=

 3次元の描画はポリゴンの表示が基本になっている。また、ポリゴンは一般的に三角形の面をつなげたものが使われる。三角形は頂点の位置が決まれば自動的に面の位置も形も決まるため、実際に計算するのは頂点の位置だけで良い。この頂点の位置を計算するのが「頂点シェーダー」である。

 頂点シェーダーの役割は、「モデルの頂点の位置を、画面上の位置に変換すること」である。頂点の位置は、「モデルの位置(ベース座標)」や「モーションによる変形(ボーン計算)」、「カメラの位置(投影計算)」などで変化する。これらの全てを考慮し、「画面上ではどの位置に頂点が来るか」を計算するのが頂点シェーダーの基本的な処理となる。


 頂点シェーダーにおいて「頂点」として扱われる情報は実際には「位置」だけではないが、その点についてはあとで「頂点」の項目で説明する。


=ラスタライズ=

 頂点シェーダーの後には「ラスタライズ」という処理が入り、その後にピクセルシェーダーに移ることになる。


 TVやモニターなどの画面は細かいピクセル(ドット)の表示が並んでいる。つまり、画面に表示する際にはこのピクセルに合わせて色を並べる必要がある。この「ピクセルの列にする」という処理に該当するのが「ラスタライズ」である。

 頂点シェーダーの処理が済めば、全ての頂点の位置は決定する。つまり、全ての三角形の面の位置と形状が決まる。しかし、あくまで「三角形の形状」が決まるだけで「どういうピクセルの並びか」まで決まるわけではない。そこで、その「三角形の形状」から「ピクセルの並び」に変換するのがラスタライズの処理となる。

 この処理は基本的にシステム側で行われるため、通常のプログラミングではわざわざ作る必要はない。(というか大抵の場合はこちら側ではいじれない)


ピクセルシェーダー=

 上のラスタライザによって「ピクセルの並び」までは求まった。あとはそれらのピクセルに対し、「実際に表示する色」を決めれば描画は完了である。そして、それを求めるのが「ピクセルシェーダー」の役割である。

 ピクセルシェーダーの役割は「色を計算すること」である。一般的には「テクスチャ(=画像)から"テクスチャ座標"の位置にある色を持ってくる」という処理になるが、他にも独自に色を設定したり、陰になっている部分を暗くしたり、半透明にしたり様々な処理が行われる。


 しかし、「テクスチャ座標」はどうやって計算すれば良いのだろうか?実は「テクスチャ座標」はピクセルシェーダーにパラメータとして渡されるので、独自に計算する必要はない。ならばそのパラメータはどのようにして計算されたのだろうか?そこで重要になってくるのが「頂点」の概念である。



=頂点=

 モデルのデータの「頂点」には「位置(3次元座標)」以外の色々なパラメータを入れることができる。前述の「テクスチャ座標」もそうだし、テクスチャを貼らない場合に使う色を「頂点カラー」として設定することもできる。他にもモーション用に色々な設定などがあるが、ともかくシェーダにおける「頂点」とは「位置」のことではなく「位置を含む、色んな情報」のことである。


 「テクスチャ座標」がピクセルシェーダに渡るまでの流れを考えるため、三角形を2つ組み合わせた正方形の場合を考えてみる。

 正方形なので「位置」は「左上」「右上」「左下」「右下」の4つの座標になる。厳密には、三角形が2つなので頂点の数は6つになり、このうち2つは重複する。ただ、ここではひとまずこの4つで考える。(実際、4種類になるような設定方法がある)
 「テクスチャ座標」はどうするかというと、これもそのまま「左上の頂点」には「テクスチャの左上の座標」を入れる。つまり、データの設定の段階では「テクスチャ座標」も4種類しか設定されない。

 しかし、ポリゴンを表示する場合、全てのピクセルにテクスチャ座標を渡す必要がある。そこで、ラスタライズの時点で「このピクセルはこの頂点とこの頂点の中間くらいにあるから、テクスチャもそれらの中間くらいの位置を参照する」という感じで補間を行い、全てのピクセルの「テクスチャ座標」を計算している。(つまり、最初の設定さえしておけば自動でそれぞれのピクセルのテクスチャ座標は計算してもらえる)

 他のデータについても同じように補間される。例えば「頂点カラー」は頂点ごとに色を指定できるため、補間が実行されると色の補間が起こりグラデーションができる。



=まとめ=

 3次元描画の流れをまとめると、

  1. 頂点シェーダで「ポリゴンの頂点の位置」を「画面上の位置」に変換する
  2. ラスタライザが「ポリゴン」を「ピクセルの並び」に変換する
  3. ピクセルシェーダで「ピクセルの色」を求める

 という風になる。


 入出力に注目すると、頂点シェーダは「入力:頂点」「出力:頂点」、ラスタライザは「入力:頂点」「出力:ピクセル」、ピクセルシェーダは「入力:ピクセル」「出力:ピクセル」となる。


 つまり、頂点シェーダーとピクセルシェーダを一つにまとめられないのは、頂点シェーダーが「頂点」を処理するのに対し、ピクセルシェーダーは「ピクセル」を処理するからだ。字面を見れば実にそのまんまである。


=あとがき=

 昔の自分が知りたかったのは「3次元描画の流れ」と、その中での「シェーダー」の立ち位置だった。書籍では「投影変換」や「クリッピング」など細かい部分まで書いてあり、詳細はわかるものの全体の大まかな流れを理解するには不便だった。ということで、上のようなやや粗い粒度の説明を書きたかったので書いてみた。


=追記=

 マテリアルの説明も書いてみた→説明しよう!マテリアルとはッ! - Master of None