ModelIO框架不起作用

时间:2016-01-02 03:27:53

标签: swift .obj metal metalkit

我正在尝试使用MetalModelIO(在OS X 10.11上)导入3D模型文件并使用MetalKit呈现它们,但我从这些框架中看到的行为(特别是ModelIO)并不像预期的那样。

我可以导入.obj文件并将它们转换为MetalKit网格而不会导致任何错误,但网格(至少在渲染下)似乎只是三角形的大粉丝单点。下面屏幕截图中的模型应该是“Suzanne”猴头的细分版本: Incorrectly imported .obj file

在检查时,导入文件中MDLSubmesh的顶点索引没有任何意义。连续的索引集合始终引用索引0处的顶点,有时在同一组索引中多次,这将解释渲染期间的外观。我已确认此.obj文件可以很好地导入到其他应用程序中。

我尝试导入其他3D文件格式(所有框架都正式支持),但.obj以外的任何格式都会导致NSException {MDLAsset {{}} { {1}}。

我正在使用Xcode 7.2并以OS X 10.11为目标。

1 个答案:

答案 0 :(得分:3)

我也遇到过类似的问题,虽然我是Metal的新手,但我想出了一些问题。

我正在尝试进口Melita茶壶,但我还有一个“爆炸”的面孔,而不是标志性的泡茶装置。在阅读MDLVertexBufferLayout的文档后,我找到了解决方案,其中包含:

  

网格可以将顶点数据存储在数组模型的结构中,   其中每个顶点属性的数据(例如顶点位置或   surface normal)位于一个单独的顶点缓冲区或一个数组中   结构模型,其中多个顶点属性共享相同的结构   缓冲液中。

     
      
  • 在数组结构中,网格的vertexBuffers数组包含   几个MDLMeshBuffer对象,以及网格的vertexDescriptor对象   包含每个缓冲区的单独MDLVertexBufferLayout对象。

  •   
  • 在结构数组中,网格包含单个顶点缓冲区,   它的描述符包含一个顶点缓冲区布局对象。至   识别缓冲区中的哪些字节引用哪些顶点和顶点   属性,使用布局的步幅与格式和   描述符顶点属性的偏移属性。

  •   

通过查看.layouts的默认实现的.attributesMDLVertexDescriptor属性,他们为每种属性类型创建一个缓冲区(如上面引用的第一种情况) ),我想使用混合模式。

我用我自己的阵列手动设置.layouts.attributes,然后,我得到了......半个梅丽塔锅?

Half-baked implementation... get it!?

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)

如果我设法渲染整个内容,我会更新我的帖子。

编辑:立即投放

Holy shi---

Whelp,这个错误就在我的最后,我在索引计数中错了:

//// 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文件,所以问题是:我上面提到的每个属性的单独缓冲,或者代码中完全不同的问题。