2017-10-31 13 views
3

私はiOS/OSX用のMetalを学びました。私はRay Wenderlichのチュートリアル(https://www.raywenderlich.com/146414/metal-tutorial-swift-3-part-1-getting-started)に従って始めました。このチュートリアルはうまくいきますが、MTLVertexAttributeDescriptorsについて言及していません。MTLVertexAttributeDescriptorsは必要ですか?彼らはなぜ必要なのですか?

私自身のアプリケーションを開発しているので、私は奇妙な不具合を起こしています。私がMTLVertexAttributeDescriptorsを使用しないという事実が問題に関連しているかどうかは疑問です。

どのような違いがありますか?私は様々な頂点構造を持つ様々なシェーダを作ることができましたが、私はこれらのことについても知らなかったのです。

シェーダで使用するために頂点コンポーネントのレイアウトを記述するためにそれらを使用することがわかっています。例えば、シェーダはこの構造体を頂点に使うことができ、それは下の関数の頂点記述子に設定されます。

typedef struct 
{ 
    float3 position [[attribute(T_VertexAttributePosition)]]; 
    float2 texCoord [[attribute(T_VertexAttributeTexcoord)]]; 
} Vertex; 

class func buildMetalVertexDescriptor() -> MTLVertexDescriptor { 

    let mtlVertexDescriptor = MTLVertexDescriptor() 

    mtlVertexDescriptor.attributes[T_VertexAttribute.position.rawValue].format = MTLVertexFormat.float3 
    mtlVertexDescriptor.attributes[T_VertexAttribute.position.rawValue].offset = 0 
    mtlVertexDescriptor.attributes[T_VertexAttribute.position.rawValue].bufferIndex = T_BufferIndex.meshPositions.rawValue 

    mtlVertexDescriptor.attributes[T_VertexAttribute.texcoord.rawValue].format = MTLVertexFormat.float2 
    mtlVertexDescriptor.attributes[T_VertexAttribute.texcoord.rawValue].offset = 0 
    mtlVertexDescriptor.attributes[T_VertexAttribute.texcoord.rawValue].bufferIndex = T_BufferIndex.meshGenerics.rawValue 

    mtlVertexDescriptor.layouts[T_BufferIndex.meshPositions.rawValue].stride = 12 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshPositions.rawValue].stepRate = 1 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshPositions.rawValue].stepFunction = MTLVertexStepFunction.perVertex 

    mtlVertexDescriptor.layouts[T_BufferIndex.meshGenerics.rawValue].stride = 8 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshGenerics.rawValue].stepRate = 1 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshGenerics.rawValue].stepFunction = MTLVertexStepFunction.perVertex 

    return mtlVertexDescriptor 
} 

しかし、たとえMTLVertexDescriptorセットアップなしで、シェーダは既に配列に頂点バッファと頂点の位置/ TEXCOORDコンポーネントにアクセスすることができます。頂点バッファを設定するだけで、シェーダはすべてのコンポーネントにアクセスできます。だから、ディスクリプタは何が良いですか?

答えて

3

もちろん、さまざまなやり方があります。頂点記述子は、その1つにのみ使用されます。

例えば、頂点関数は次のように宣言されるかもしれない:

vertex MyVertexOut vertex_func(device const float3 *positions [[buffer(0)]], 
           device const float2 *texCoords [[buffer(1)]], 
           uint vid [[vertex_id]]) 
{ 
    // use positions[vid] and texCoords[vid] to fill in and return a MyVertexOut structure 
} 

これは、頂点属性が別のバッファ、特定のレイアウトのそれぞれに供給されることを指示します。

あなたも行うことができます:

struct MyVertexIn 
{ 
    float3 position; 
    float2 texCoord; 
}; 
vertex MyVertexOut vertex_func(device const MyVertexIn *vertexes [[buffer(0)]], 
           uint vid [[vertex_id]]) 
{ 
    // use vertexes[vid].position and vertexes[vid].texCoord to fill in and return a MyVertexOut structure 
} 

これは頂点属性がMyVertexInのレイアウトに一致する構造体の単一バッファに供給することが決まります。

上記のいずれも、頂点記述子を必要とするか、または使用しません。それは完全に無関係です。しかし、あなたもこれを行うことができます

struct MyVertexIn 
{ 
    float3 position [[attribute(0)]]; 
    float2 texCoord [[attribute(1)]]; 
}; 
vertex MyVertexOut vertex_func(MyVertexIn vertex [[stage_in]]) 
{ 
    // use vertex.position and vertex.texCoord to fill in and return a MyVertexOut structure 
} 

attribute(n)stage_in属性の使用に注意してください。これは、頂点属性がどのように供給されるかを指示するものではありません。むしろ、頂点記述子は、1つ以上のバッファから頂点属性へのマッピングを記述する。マッピングでは、変換と展開も実行できます。たとえば、上記のシェーダコードでは、のフィールドがfloat3であることが指定されていますが、バッファにはhalf3の値(またはその他のさまざまなタイプ)が含まれている可能性があり、自動的に変換が行われます。

同じシェーダを異なる頂点ディスクリプタで使用することができるため、バッファ間で頂点属性の分布が異なります。これは、さまざまなシナリオに柔軟性を提供します。頂点属性は、(最初​​の例と同様に)別のバッファと、同じバッファにインターリーブされる別のバッファに分割されます(2番目の例と同様)。その他

柔軟性と余分なレベルの抽象化が必要ない場合は、頂点ディスクリプタを処理する必要はありません。彼らはそれらを必要とする人々のためにそこにいる。

+0

ありがとうございました - [[stage_in]]と[[buffer]]の構文の違いについては、私は不思議でした。残念ながら、これはまた、頂点記述子の不足がおそらく私のグリッチの原因ではないことを意味します。 – bsabiston

関連する問題