3-5. シェーダ

今回扱うのはパイプラインの中の主役と言っても過言ではないシェーダです。

元々の語義としては「陰影処理を行うもの」ですが、実際としてはなんでもできます。前節でパイプラインとは「点の集まりで出来た図形を色のついたピクセルの集合に変換するもの」として紹介しましたが、シェーダはそのパイプラインの中において、あの点とこの点をあっちに動かしたりこっちに動かしたり、あのピクセルこのピクセルを赤に塗ったり青に塗ったりする役割を果たします。

昔はシェーダも簡素なことしかせず、文字通りただの「陰影を付けるもの」であり、その処理内容もほぼ固定だったらしいのですが、今は自由にシェーダプログラムを書いてGPUに実行させることができます。空間をねじ曲げ、複雑な模様を描き、物や何かをべらぼうに増やすことさえもできます。

何でもできるようになった代わり、お決まりのような普通の処理しかしたくない場合でもそれをちゃんと書かなければなりません。デフォルト動作に任せるという選択肢は存在しないのです。自由の刑か何か?

冗談はさておき、我々はシェーダプログラムを書く必要があります。シェーダに使う言語ですが、GLSLというC言語をベースとした専用言語を使います。GLSLで書いたプログラムは、専用のソフトでSPIR-Vという中間言語にコンパイルします。Vulkanからはそれを読み込んで実行することになります。ちなみにSPIR-Vの仕様はGLSLとは独立しており、実際にはGLSL以外の言語(DirectXで使われるHLSLとか)からコンパイルすることもできます。今回は普通にGLSLからコンパイルするのですが。

シェーダには種類があります。その中で最低限必要なものとして、今回は「頂点シェーダ(バーテックスシェーダ)」と「フラグメントシェーダ」を作ります。

まずは頂点シェーダのプログラムから見ていきましょう。頂点シェーダは頂点1つごとに呼ばれ、その頂点の座標を出力します。本来はメインの方のプログラムから点の座標データを与え、シェーダでそれを加工したりするものなのですが、ここでは簡単のためシェーダプログラムの中に座標値をハードコーディングします。

出力先は2次元の画像なのになぜ点の位置が4次元座標なのかというのは一旦置いておいて、最初の2成分に注目しましょう。(0.0, -0.5)、(0.5, 0.5)、(-0.5, 0.5)の3点ですね。

Vulkanにおいては画像の一番左上が(-1.0, -1.0)、右下が(1.0, 1.0)になります。つまり、このシェーダに3点の座標を出力させれば以下のような座標データを出力します。

この連続した3点は1つの三角形として認識してくれますので、あとは色を付けたら三角形が描けそうです。

次はフラグメントシェーダです。フラグメントシェーダはピクセル1つごとに呼ばれ、そのピクセルの色を決定します。

色はRGBA(RGBとαチャンネル)の4次元ベクトルで表現されます。それぞれの値は0.0~1.0の実数で表現されます。ここではRが1.0、GBが0.0なので全て真っ赤になります。

それぞれのソースコードをshader.vert,shader.fragというファイル名で保存します。これをSPIR-Vにコンパイルします。Vulkan SDKに付属のglslcというツールを使います。VulkanインストールディレクトリのBinディレクトリ下にあるはずです。パスを通すなどして以下のコマンドを実行しましょう。

-oオプションは出力ファイル名の指定です。これでvert.spvとfrag.spvというそれぞれのSPIR-V形式のシェーダファイルが出来ました。これをメインの方のプログラムから読み込みます。

ファイルのサイズと中身のデータさえ取れればいいので、その方法はC言語のファイルポインタだろうがWindowsAPIだろうがシステムコールだろうが何でも良いのですが、ここではC++の標準ライブラリを使用します。

インクルードするヘッダを追加しましょう。

そして読み込みます。まずは頂点シェーダから。

読み込んだら、そのデータからシェーダモジュールなるオブジェクトを作成します。シェーダモジュールは vk::DevicecreateShaderModule メソッドで作成できます。

これでSPIR-V形式の頂点シェーダのデータから、頂点シェーダを表すシェーダモジュールが作成できました。

フラグメントシェーダも同様にします。

ここまでをとりあえず実行してみましょう。もしも実行時にエラーが出る場合は、ファイルの名前や場所が間違っていないかどうかを確認してください。エラーが出なければ成功です。

 

読み込んだシェーダをパイプラインに組み込みましょう。前節で書いたパイプラインの作成処理に追加します。

vk::PipelineShaderStageCreateInfo の pName に”main”という文字列を入れていますが、これは「このシェーダはmain関数から始める」という意味です。

これでパイプラインにシェーダが追加できました。おめでとうございます。


この節ではシェーダの追加をやりました。次節ではイメージビューの作成をやります。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です