やっていくVulkan入門

5-10. デスクリプタ(データの準備)

この節および次節においてデスクリプタというものをやります。ある程度長い内容なので節を分けました。

ここまでシェーダに値を渡す方法を学んできましたが、いずれも位置とか色とか、「頂点ごとに異なるデータ」を渡していました。しかし実際に3Dモデルを描画しようとしたたとき、必要になるのはそれだけではないはずです。

例えばキャラクターの3Dモデルを描画するとして、そのモデルの立ち位置であるとか、関節の角度であるとか、カメラの位置といったデータも無ければ描画処理は出来ません。そして、そのようなデータは各頂点のものではなくモデルやワールド全体で共通のデータのはずです。こうしたデータはユニフォーム変数と呼ばれます。これらは頂点バッファで渡すものではありません。

こうしたタイプのデータはデスクリプタという仕組みでシェーダに渡します。重要な内容なのでしっかり理解しましょう。


データの準備

今回は簡単な例として、「2次元座標を渡してそれによって前回描いた長方形の位置を移動させる」ことを目指します。

とりあえずデータを準備しましょう。

struct SceneData {
    Vec2 rectCenter;
};

SceneData sceneData = { Vec2{ 0.3, -0.2 } };

例なので値は適当です。


頂点シェーダ

あとで用いる頂点シェーダを先に示しておきます。

まだ使えませんが、先ほどのデータをこんな形でシェーダから利用できるという所を理解してもらえればと思います。

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(set = 0, binding = 0) uniform SceneData {
    vec2 rectCenter;
} sceneData;

layout(location = 0) in vec2 inPos;
layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragmentColor;

void main() {
    gl_Position = vec4(sceneData.rectCenter + inPos, 0.0, 1.0);
    fragmentColor = inColor;
}

sceneDataという名前の構造体変数として値を受け取っています。uniformという指定がありますね。これがユニフォーム変数であることを表しています。これはinoutなどと同じ、ストレージ修飾子と呼ばれるものの一種です。

また、set = 0, binding = 0という指定も付いています。これはユニフォーム変数の位置を表すもので、頂点データのlocationなどと同様データを結びつけるのに必要になります。頂点バッファでもバインディングという言葉が出てきましたが、このbindingはそれとはまた別の話なので混同しないようにしましょう。

余談: GLSLのシェーダ変数の書き方

GLSLのシェーダ変数はいずれもこのような形式になっています。

layout修飾子 ストレージ修飾子 型 変数名;

最初に示した構造体を渡す方のコードも、単に型の部分が構造体定義になっていただけという訳です。

今回渡すのは大きな構造体ではなく変数1つだけなので、以下のように書いても構いません。

layout(set = 0, binding = 0) uniform vec2 rectCenter;

こっちの方がinoutの変数と見た目が似ていて分かりやすいかもしれませんね。

こちらの書き方の場合はこのように使います。

gl_Position = vec4(rectCenter + inPos, 0.0, 1.0);

この節ではシェーダに渡すデータの準備を行いました。

シェーダにデータを渡すための処理を書いていないので、まだ頂点シェーダは変えないでおきましょう。