5

之间有什么联系:

  1. [[stage_in]]在金属着色器中使用
  2. 使用MTLVertexDescriptor
  3. 使用MTKMesh

例如

  1. [[stage_in]]不使用就可以使用MTLVertexDescriptor吗?
  2. 是否可以在不使用的MTLVertexDescriptor情况下使用MTKMesh,但可以使用基于自定义结构的数据结构的数组?比如struct Vertex {...}, Array<Vertex>
  3. MTKMesh不使用就可以使用MTLVertexDescriptor吗?例如使用相同的基于结构的数据结构?

我没有在互联网上找到这些信息,而且金属着色语言规范甚至不包括“描述符”或“网格”这两个词。

4

1 回答 1

12
  1. 否。如果您尝试从没有顶点描述符的管道描述符创建渲染管道状态,并且相应的顶点函数有[[stage_in]]参数,则管道状态创建调用将失败。

  2. 是的。毕竟,当您绘制s 时MTKMesh,您仍然有义务使用由网格的组成部分ssetVertexBuffer(...)包裹的缓冲区进行调用。MTKMeshBuffer您可以轻松地创建MTLBuffer自己并将自定义顶点结构复制到其中。

  3. 是的。[[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;我提到这一点是因为它可能会令人困惑。

这是您可以创建顶点描述符以告诉模型 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 类型被填充以用于对齐目的(具体而言,a 的步幅float316个字节,而不是我们在顶点描述符中要求的 12 个字节)。

于 2018-01-26T21:46:19.263 回答