之间的联系是什么:

  • 在金属着色器中使用[[stage_in]]
  • 使用MTLVertexDescriptor
  • 使用MTKMesh

  • 例如
  • 是否可以不使用[[stage_in]]而使用MTLVertexDescriptor
  • 是否可以不使用MTLVertexDescriptor而使用MTKMesh,而是使用基于自定义结构的数据结构的数组?如struct Vertex {...}, Array<Vertex>
  • 是否可以不使用MTKMesh而使用MTLVertexDescriptor?例如使用相同的基于结构的数据结构?

  • 我在互联网上找不到此信息,并且“金属底纹语言规范”甚至没有包含“描述符”或“网格”一词。

    最佳答案

  • 否。如果尝试从没有顶点描述符的管道描述符创建渲染管道状态,并且相应的顶点函数具有[[stage_in]]参数,则管道状态创建调用将失败。
  • 是的。毕竟,当您绘制MTKMesh时,您仍然必须使用网格的组成setVertexBuffer(...)包裹的缓冲区来调用MTKMeshBuffer。您可以轻松地自己创建一个MTLBuffer并将您的自定义顶点结构复制到其中。
  • 是的。不用[[stage_in]]参数,而是使用[[buffer(0)]]类型的MyVertexType *属性(假设所有顶点数据在单个顶点缓冲区中交错)以及一个[[vertex_id]]参数(可告诉您在哪里索引该缓冲区) 。

  • 这是从渲染命令编码器上的MTKMesh设置顶点缓冲区的示例:
    for (index, vertexBuffer) in mesh.vertexBuffers.enumerated() {
        commandEncoder.setVertexBuffer(vertexBuffer.buffer, offset: vertexBuffer.offset, index: index)
    }
    
    vertexBuffer的类型为MTKMeshBuffer,而buffer属性的类型为MTLBuffer;我提到这一点是因为它可能会造成混淆。

    您可以通过以下一种方式创建顶点描述符,以告知Model I/O和MetalKit布置要加载的网格数据:
    let mdlVertexDescriptor = MDLVertexDescriptor()
    mdlVertexDescriptor.attributes[0] = MDLVertexAttribute(name: MDLVertexAttributePosition, format: MDLVertexFormat.float3, offset: 0, bufferIndex: 0)
    mdlVertexDescriptor.attributes[1] = MDLVertexAttribute(name: MDLVertexAttributeNormal, format: MDLVertexFormat.float3, offset: 12, bufferIndex: 0)
    mdlVertexDescriptor.attributes[2] = MDLVertexAttribute(name: MDLVertexAttributeTextureCoordinate, format: MDLVertexFormat.float2, offset: 24, bufferIndex: 0)
    mdlVertexDescriptor.layouts[0] = MDLVertexBufferLayout(stride: 32)
    

    您可以创建相应的MTLVertexDescriptor,以创建适合于渲染此类网格物体的渲染管道状态:
    let vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(mdlVertexDescriptor)!
    

    这是与该布局匹配的顶点结构:
    struct VertexIn {
        float3 position  [[attribute(0)]];
        float3 normal    [[attribute(1)]];
        float2 texCoords [[attribute(2)]];
    };
    

    这是一个存根顶点函数,使用了这些顶点之一:
    vertex VertexOut vertex_main(VertexIn in [[stage_in]])
    {
    }
    

    最后,这是一个顶点结构和顶点函数,可用于在没有顶点描述符的情况下渲染完全相同的网格数据:
    struct VertexIn {
        packed_float3 position;
        packed_float3 normal;
        packed_float2 texCoords;
    };
    
    vertex VertexOut vertex_main(device VertexIn *vertices [[buffer(0)]],
                                 uint vid [[vertex_id]])
    {
        VertexIn in = vertices[vid];
    }
    

    请注意,在最后一种情况下,我需要将结构成员标记为压缩,因为默认情况下,为对齐目的而填充Metal的simd类型(具体来说,float3的跨度为 16 字节,而不是我们在顶点中要求的12字节)描述符)。

    08-06 03:56