MTLVertexDescriptorと[[attribute(n)]]属性を使用した頂点関数の引数データの配置方法の明確化

Aug 24 2020

次のMSLを検討してください。

#include <metal_stdlib>
using namespace metal;

struct VertexIn {
    float3 position     [[attribute(0)]];
    float3 normal       [[attribute(1)]];
    float3 color        [[attribute(2)]];
};

// Void just for demonstration
vertex void vertexFunc(const VertexIn vIn [[stage_in]]) {}

MTLBufferオブジェクトとMTLVertexDescriptorオブジェクトの概念は明確です。後者は、Metal構造体(VertexInこの場合)のデータがさまざまなMTLBufferオブジェクトにどのように分散されるかを説明しています。次に、[[stage_in]]引数の属性を構造体のタイプの頂点関数に追加すると、データに一致する構造体のメンバーを使用してインスタンスが作成されます。

:私は1つの質問持って[[stage_in]]、自動的に特定のバッファを使用して、すべての属性(の合計サイズによってバッファを相殺totalSizeすることによって)totalSize * [[vertex_id]]各内のMTLBuffer属性のレイアウト情報とデータを構造体のメンバーを結合する前に?私はこれが起こるに違いないと思います、しかし私はこれがで起こるかどうか/どのように/いつ起こるかについて言及するものをまだ見つけていません[[stage_in]]

たとえば、

let descriptor = MTLVertexDescriptor()

// Position
descriptor.attributes[0].format = .float3
descriptor.attributes[0].bufferIndex = 0
descriptor.attributes[0].offset = 0

// Normal
descriptor.attributes[1].format = .float3
descriptor.attributes[1].bufferIndex = 0
descriptor.attributes[1].offset = MemoryLayout<vector_float3>.stride

// Color
descriptor.attributes[2].format = .float3
descriptor.attributes[2].bufferIndex = 1
descriptor.attributes[2].offset = 0

descriptor.layouts[0].stride = 2 * MemoryLayout<vector_float3>.stride
descriptor.layouts[1].stride = MemoryLayout<vector_float3>.stride

2つのバッファを設定します。1つはインターリーブ位置と通常のデータを使用し、もう1つはカラーデータを使用します。頂点シェーダーは(buffer0Start) + n * (sizeof(float3) + sizeof(float3))、バッファ0と(buffer1Start) + n * (sizeof(float3))バッファ1でn番目の頂点のデータを受信し[[stage_in]]ますか?

回答

Leftasanexercise Aug 25 2020 at 08:01

これが事実であるように思われます。Appleの「MetalShadingLanguageSpecification」バージョン2.2の87ページのセクション5.2.4には次のように書かれています。

頂点関数は、頂点IDとインスタンスIDを使用して、頂点関数に引数として渡されたバッファーにインデックスを付けることにより、頂点ごとの入力を読み取ることができます。頂点ごとの入力をアセンブルし、それらを引数として頂点関数に渡すには、[[stage_in]]属性を使用して入力を宣言します。