シェーダー: shader)はグラフィックスパイプラインを構成する各ステージの挙動を記述したプログラムである[1][2]

また狭義にはグラフィックスパイプライン中のシェーディング(陰影処理)に関する挙動を記述したプログラムを指す[3]

概要

3DCGは様々な要素技術の集まりである。物体を三角形の集合で表現するモデリング、動きを計算するアニメーション・物理演算、見た目を生成するレンダリングなどである。レンダリングは複数の段階からなるパイプライン(レンダリングパイプライン)で成っており、現代のレンダリングパイプラインはプログラム可能なステージを多数含んでいる。これにより柔軟なグラフィックスが実現可能になっている。

このプログラム可能なステージの挙動を記述したスクリプトがシェーダーである[1]。実現したいグラフィックスに合わせて各ステージの挙動を専用のシェーディング言語で記述し、このプログラムを実行時にGPU等のハードウェアへ引き渡すことで、レンダリングパイプラインが頂点群やフラグメント群に対してこれら指示を実行し3DCGの見た目が生成される。

シェーダーで可能な処理はハードウェアあるいはそれを抽象化したグラフィックスAPIに規定される。基本的には各ステージで扱う対象が定められており[1]#分類)、またステージに応じて典型的な処理が様々存在する(例: カメラを起点とした座標変換、テクスチャマッピング、ライティング)。他方で現代のシェーダーはかなり自由度が高く、例えばピクセルシェーダーにおいて入力に含まれている色情報をすべて捨て去って真っ黒なピクセルを出力することも可能であるし、最新の研究に基づいた新しいライティングアルゴリズムを記述することもできる。

現代のグラフィックスパイプラインはプログラム可能なステージが多く柔軟性が高い反面、基本的な処理含めてシェーダーに記述する必要があり手間がかかる。ゲームエンジン等のミドルウェアがこれを簡略化する役割を担うことがある。その場合、エンジンがレンダリングパイプラインの一部のみをプログラマに公開する。すなわちエンジンがパイプラインを内部的に持ちエンジン側で典型的な処理を用意する。これにより簡略化しつつ、各ステージ内でプログラマがよく関与する部分に関してのみ追加でシェーダーを差し込めるようにする。これにより典型的な処理の記述を避けつつ柔軟性を確保できる。差し込み可能な領域がシェーディング(陰影処理)である場合が多いため、「シェーダー」という語を「陰影処理に関する挙動を記述したプログラム」という意味で扱う場合もある[3]

shade」とは「次第に変化させる」「陰影・グラデーションを付ける」という意味で、「shader」は頂点色やピクセル色などを次々に変化させるもの(より具体的に、狭義の意味で言えば関数)を意味する。

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

用途と使い分け

シェーダー内で実装されるグラフィックスアルゴリズムは用途に応じて使い分けられる。

映画などのプロダクション用途のシェーダーでは、時間はかかるが高品質でリアリティの高い結果を生成する。レンダリング方程式英語版に基づくレイトレーシングラジオシティフォトンマッピングなど、より厳密な大域照明(グローバルイルミネーション)ベース・物理ベースの陰影計算モデルが用いられる。例えば、PIXARRenderManはグローバルイルミネーションをサポートしている[4]

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

リアルタイム用途のシェーダーはCGプロダクションソフトウェアのプレビューにも用いられる。プロダクション用シェーダーの代わりにリアルタイム用シェーダーを用いることで素早いプレビューが可能になる。例えばAutodesk 3ds MaxAutodesk MayaAutodesk Softimage、およびNewTek LightWave 3Dがプレビュー機能を提供している。

2DCGソフトウェアにもアクセラレータとしてしばしば導入される(例: Adobe PhotoshopAdobe Flash)。GUIベースオペレーティングシステム (OS) のデスクトップ合成エンジンや標準2DグラフィックスAPI、具体的にはWindows Aero/Direct2D (Windows) やQuartz Extreme/Core Image (macOS) がその一例である。

分類

シェーダーは対応するステージによって入出力や利用可能な機能が異なる。これに基づいてシェーダーは以下のように分類できる。なお、各シェーダーの具体的な仕様や制約はグラフィックスAPI/ハードウェアごとに異なるため、ここで紹介するのは Direct3D / OpenGL / Vulkan におおよそ共通する振る舞いに留まる(詳細は各仕様の記事を参照)。

シェーダーステージ

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

さらに見る ステージ名, 入力 ...
表: シェーダーステージ
ステージ名 入力 出力 注記
頂点シェーダー 頂点 頂点
テッセレーション[14] プリミティブ プリミティブ しばしば "制御シェーダー" + "テッセレーション固定機能"
ジオメトリシェーダー[15] プリミティブ プリミティブ
(ラスタライズ) プリミティブ フラグメント 固定機能
フラグメントシェーダー フラグメント フラグメント
閉じる

OpenGL 3.2以降とDirect3D 10[16]以降では3種類のシェーダーを使用できる。シェーダー間の入出力関係はグラフィックスパイプライン#ステージを参照。

頂点シェーダー

頂点シェーダー: Vertex Shader)は各頂点を処理するシェーダーである[17]バーテックスシェーダーとも。

頂点シェーダーはオブジェクトを構成する頂点を入力とし、様々な処理おこない、頂点を出力する[17]。例えば3次元空間座標法線ベクトル・色・テクスチャマッピング座標を入力として受け付ける。グラフィックスAPIによってはテクスチャへの副次的アクセスが用意されている。処理として典型的にはモデル変換・ビュー変換投影変換をおこない[18]、古典的には頂点単位のライティングもおこなう。

ジオメトリシェーダー

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

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

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

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

ピクセルシェーダー

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

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

ピクセルシェーダーは深度(奥行き)も操作できる。深度の操作はレンダリングパイプラインの最適化へ影響する(例: 深度テストの実行タイミングを左右する)ため、シェーディング言語/グラフィックスAPIによってはフラグの明示が求められる(例: SPIR-V/Vulkan[19])。

テッセレーションシェーダー

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

コンピュートシェーダー

コンピュートシェーダー: Compute shader)はコンピュートパイプラインを構成する各ステージの挙動を記述したプログラムである[1]

コンピュートシェーダーは汎用並列処理(GPGPU)を目的としており、計算の入出力をグラフィックスパイプラインと共有する場合もある。あくまでシェーダーの一種でありシェーディング言語で記述される。APIとしては OpenGL 4.3以降、OpenGL ES 3.1以降、およびDirect3D 11以降で提供される。Direct3DではDirect3D APIを含めた総称としてDirectComputeと呼ばれている。

GPGPU専用のAPI・言語としてはCUDAOpenCLがよく知られている。

歴史

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

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

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

各シェーダーステージが扱えるリソースの範囲も時代とともに拡大している。シェーダーモデル3.0(DirectX 9.0c、OpenGL 2.x世代)で導入されたVertex Texture Fetch (VTF) [29]により、頂点シェーダーステージでテクスチャデータを参照できるようになった。シェーダーモデル4.0(DirectX 10世代)以降では、VTFはバッファデータの参照とともに標準化された[30](OpenGLは3.1でVTFを標準化し、頂点シェーダーで少なくとも16個のTIUを使えるようになった)。さらに、OpenGL 4.2ではすべてのシェーダーステージにおいてイメージオブジェクトに対するロード/ストアを可能にする機能が標準化された[31]。DirectXにおいても、バージョン11.1にて、ピクセルシェーダーやコンピュートシェーダーだけでなく、すべてのシェーダーステージにおいて各種リソースに対する書き込みが可能になった[32]

関連項目

脚注

Wikiwand in your browser!

Seamless Wikipedia browsing. On steroids.

Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.

Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.