【问题标题】:ModelIO Framework Not WorkingModelIO 框架不工作
【发布时间】:2016-04-06 08:42:18
【问题描述】:

我正在尝试导入 3D 模型文件并使用 Metal 使用 ModelIOMetalKit 渲染它们(在 OS X 10.11 上),但是我从这些框架中看到的行为(特别是 ModelIO)不如预期。

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

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

我已尝试导入其他 3D 文件格式(框架都正式支持),但除 .obj 以外的任何格式都会在调用 MDLAssetinit() 时导致未捕获的 NSException

我正在使用 Xcode 7.2 并针对 OS X 10.11。

【问题讨论】:

  • 很难从您发布的内容中判断出来,但有可能这是一个 ModelIO 错误。我建议filing it 并附上 obj 文件以防万一。
  • @rickster 谢谢。我只是尝试编写自己的代码来解析文件并且它工作正常(无需渲染修改),所以我遇到的 ModelIO 问题要么是一个错误,要么是我不理解如何正确使用 API(尽管我相信我是)。
  • 发布一些代码,您是如何使用 MetalIO 以及如何绘制它的。尝试在 Apple 网站的 MetalIO 示例中使用此网格。

标签: swift .obj metal metalkit


【解决方案1】:

我也遇到过类似的问题,虽然我是 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 文件,所以问题要么是:我上面提到的每个属性单独缓冲的问题,要么是代码中完全不同的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多