🌋

VulkanのMesh shaderに入門してみた

2022/12/30に公開

コード

Vulkanに追加されたばかりのVK_EXT_mesh_shader拡張機能を使ってみました。
コードはこちら。
https://github.com/yknishidate/vk_mesh_shader

参考資料

VulkanのMesh shader拡張機能についての資料を紹介します。ここには上げていませんがDirectX方面の資料も参考になりそうです。

Khronosの説明ページ

概要だけですが一読すると良さそうです。ちなみにこのページで紹介されているNVIDIAのサンプルは少し発展向けなので後回しで良いと思います。
https://www.khronos.org/blog/mesh-shading-for-vulkan

Khronosのウェビナー

ウェビナーの動画と資料を見ると実装の雰囲気もなんとなく分かります。
https://www.youtube.com/watch?v=OfqpkyoARFc&t=899s

https://www.khronos.org/assets/uploads/developers/presentations/how-to-use-mesh-shaders.pdf

SaschaWillems/Vulkan

Khronosのサンプルリポジトリにはmesh shaderがまだ含まれていないようなので、SaschaWillemsのサンプルが一番読みやすいです。
https://github.com/SaschaWillems/Vulkan/tree/master/examples/meshshader

使ってみる

四角ポリゴンを三角形にtriangulateしてレンダリングする処理を書いてみます。ここではTask shaderは使わずに、Mesh shaderだけにしました。解説はコメントで。

#version 450

// 拡張機能を有効化する
#extension GL_EXT_mesh_shader : require

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

// 出力プリミティブを三角形に設定する
// linesやpointsに設定することもできる
// 出力する頂点数と三角形の数も設定する
// 1枚の四角ポリゴンをtriangulateするため4つの頂点と2つ三角形を出力する
layout(triangles, max_vertices = 4, max_primitives = 2) out;

// Vertex shaderと異なり頂点情報もただのバッファとして入力される
layout(binding = 0) buffer Vertices{vec4 v[];} vertices;
layout(binding = 1) buffer Indices{uint i[];} indices;

// 頂点ごとに出力したい情報
layout(location = 0) out VertexOutput
{
    vec4 color;
} vertexOutput[];

void main()
{
    // CPU側からは
    // vkCmdDrawMeshTasksEXT(cmdBuf, groupCountX, groupCountY, groupCountZ)
    // という形で実行される
    uint primitiveID = gl_GlobalInvocationID.x;

    uint i0 = indices.i[4 * primitiveID + 0]; 
    uint i1 = indices.i[4 * primitiveID + 1]; 
    uint i2 = indices.i[4 * primitiveID + 2];
    uint i3 = indices.i[4 * primitiveID + 3];
    
    vec4 v0 = vec4(vertices.v[i0]);
    vec4 v1 = vec4(vertices.v[i1]);
    vec4 v2 = vec4(vertices.v[i2]);
    vec4 v3 = vec4(vertices.v[i3]);
    
    // 出力する頂点数(4)とプリミティブ数(2)を設定
    SetMeshOutputsEXT(4, 2);
    
    // gl_MeshPerVertexEXTの中身を設定していく
    gl_MeshVerticesEXT[0].gl_Position = v0;
    gl_MeshVerticesEXT[1].gl_Position = v1;
    gl_MeshVerticesEXT[2].gl_Position = v2;
    gl_MeshVerticesEXT[3].gl_Position = v3;
    
    vertexOutput[0].color = vec4(1.0, 0.0, 0.0, 1.0);
    vertexOutput[1].color = vec4(0.0, 1.0, 0.0, 1.0);
    vertexOutput[2].color = vec4(0.0, 0.0, 1.0, 1.0);
    vertexOutput[3].color = vec4(0.0, 1.0, 0.0, 1.0);
    
    // 2つのプリミティブ(三角形)のインデックスを設定する
    gl_PrimitiveTriangleIndicesEXT[2*gl_LocalInvocationIndex + 0] =  uvec3(0, 1, 2);
    gl_PrimitiveTriangleIndicesEXT[2*gl_LocalInvocationIndex + 1] =  uvec3(2, 3, 0);
}

Mesh shaderへの頂点データはどのような形式でもいいため、このようなコードで簡単に四角ポリゴンをレンダリングできるようになります。

Discussion