我也遇到过类似的问题,虽然我是 Metal 的菜鸟,但我想出了一些办法。
我试图导入 Melita 茶壶,但我的脸也“爆炸”了,而不是标志性的泡茶设备。在阅读了MDLVertexBufferLayout 的文档后,我找到了解决方案,内容如下:
网格可以将顶点数据存储在数组模型的结构中,
其中每个顶点属性的数据(例如顶点位置或
表面法线)位于单独的顶点缓冲区中,或位于
结构模型,其中多个顶点属性共享相同
缓冲区。
在数组结构中,网格的 vertexBuffers 数组包含
几个 MDLMeshBuffer 对象,以及网格的 vertexDescriptor 对象
每个缓冲区都包含一个单独的 MDLVertexBufferLayout 对象。
在结构数组中,网格包含单个顶点缓冲区,
它的描述符包含单个顶点缓冲区布局对象。到
识别缓冲区中的哪些字节指的是哪些顶点和顶点
属性,将布局的步幅与格式和
描述符顶点属性的偏移量属性。
通过查看MDLVertexDescriptor 的默认实现的.layouts 和.attributes 属性,他们正在为每种属性类型创建一个缓冲区(如上面引用的第一种情况),我想使用混合模式。
我用自己的数组手动设置了.layouts 和.attributes,然后,瞧,我得到了……半个melita pot?
class func setup(meshWithDevice device: MTLDevice) -> MTKMesh
{
// Allocator
let allocator = MTKMeshBufferAllocator(device: device)
// Vertex Descriptor, tells the MDLAsset how to layout the buffers
let vertexDescriptor = MDLVertexDescriptor()
// Vertex Buffer Layout, tells how many buffers will be used, and the stride of its structs
// (the init(stide: Int) crashes in the Beta)
let vertexLayout = MDLVertexBufferLayout()
vertexLayout.stride = MemoryLayout<Vertex>.size
// Apply the Layouts
vertexDescriptor.layouts = [vertexLayout]
// Apply the attributes, in my case, position and normal (float4 x2)
vertexDescriptor.attributes =
[
MDLVertexAttribute(name: MDLVertexAttributePosition, format: MDLVertexFormat.float4, offset: 0, bufferIndex: 0),
MDLVertexAttribute(name: MDLVertexAttributeNormal, format: MDLVertexFormat.float4, offset: MemoryLayout<float4>.size, bufferIndex: 0)
]
var error : NSError? = nil
// Load the teapot
let asset = MDLAsset(url: Bundle.main.url(forResource: "teapot", withExtension: "obj")!, vertexDescriptor: vertexDescriptor, bufferAllocator: allocator, preserveTopology: true, error: &error)
if let error = error
{
print(error)
}
// Obtain the teapot Mesh
let teapotModel = asset.object(at: 0) as! MDLMesh
// Convert into MetalKit Mesh, insted of ModelIO
let teapot = try! MTKMesh(mesh: teapotModel, device: device)
return teapot
}
(XCode 8 Beta 6 中的 Swift 3.0)
如果我设法渲染整个内容,我会更新我的帖子。
编辑:现在可以使用
Whelp,这个 bug 就在我头上,我的索引计数错了:
//// Buffers
renderPass.setVertexBuffer(mesh.vertexBuffers[0].buffer, offset: 0, at: 0)
renderPass.setVertexBuffer(uniformBuffer, at: 1)
let submesh = mesh.submeshes[0]
let indexSize = submesh.indexType == .uInt32 ? 4 : 2
//// Draw Indices
renderPass.drawIndexedPrimitives(submesh.primitiveType,
indexCount: submesh.indexBuffer.length / indexSize,
indexType: submesh.indexType,
indexBuffer: submesh.indexBuffer.buffer,
indexBufferOffset: 0)
问题在于let indexSize = submesh.indexType == .uInt32 ? 4 : 2,之前我在右侧做32 : 16,但.length 属性是字节而不是位,太笨了。
无论如何,我设法用 Metal 加载了一个 Obj 文件,所以问题要么是:我上面提到的每个属性单独缓冲的问题,要么是代码中完全不同的问题。