【问题标题】:Find the Bounding Box of Submesh in iOS在 iOS 中查找 Submesh 的边界框
【发布时间】:2019-06-25 09:13:22
【问题描述】:

我正在从 obj 文件中绘制如下 3D 模型。我需要为该 obj 文件的每个子网格找到边界框。

 let assetURL = Bundle.main.url(forResource: "train", withExtension: "obj")!
 let allocator = MTKMeshBufferAllocator(device: device)
 let asset = MDLAsset(url: assetURL, vertexDescriptor: vertexDescriptor, bufferAllocator: meshAllocator)
 let mdlMesh = asset.object(at: 0) as! MDLMesh

 mesh = try! MTKMesh(mesh: mdlMesh, device: device)

  for submesh in mesh.submeshes {
//I need to find the bounding box for each Submesh
        }

如何在 iOS 中实现这一点。

【问题讨论】:

    标签: ios swift metal


    【解决方案1】:

    这是一个函数,它接受 MTKMesh 并在 模型空间 中生成 MDLAxisAlignedBoundingBoxes 数组:

    enum BoundingBoxError : Error {
        case invalidIndexType(String)
    }
    
    func boundingBoxesForSubmeshes(of mtkMesh: MTKMesh, positionAttributeData: MDLVertexAttributeData) throws -> [MDLAxisAlignedBoundingBox]
    {
        struct VertexPosition {
            var x, y, z: Float
        }
    
        var boundingBoxes = [MDLAxisAlignedBoundingBox]()
    
        var minX = Float.greatestFiniteMagnitude
        var minY = Float.greatestFiniteMagnitude
        var minZ = Float.greatestFiniteMagnitude
        var maxX = -Float.greatestFiniteMagnitude
        var maxY = -Float.greatestFiniteMagnitude
        var maxZ = -Float.greatestFiniteMagnitude
    
        let positionsPtr = positionAttributeData.dataStart
    
        for submesh in mtkMesh.submeshes {
            let indexBuffer = submesh.indexBuffer
            let mtlIndexBuffer = indexBuffer.buffer
            let submeshIndicesRaw = mtlIndexBuffer.contents().advanced(by: indexBuffer.offset)
    
            if submesh.indexType != .uint32 {
                throw BoundingBoxError.invalidIndexType("Expected 32-bit indices")
            }
    
            let submeshIndicesPtr = submeshIndicesRaw.bindMemory(to: UInt32.self,
                                                                 capacity: submesh.indexCount)
            let submeshIndices = UnsafeMutableBufferPointer<UInt32>(start: submeshIndicesPtr,
                                                                    count:submesh.indexCount)
    
            for index in submeshIndices {
                let positionPtr = positionsPtr.advanced(by: Int(index) * positionAttributeData.stride)
                let position = positionPtr.assumingMemoryBound(to: VertexPosition.self).pointee
    
                if position.x < minX { minX = position.x }
                if position.y < minY { minY = position.y }
                if position.z < minZ { minZ = position.z }
                if position.x > maxX { maxX = position.x }
                if position.y > maxY { maxY = position.y }
                if position.z > maxZ { maxZ = position.z }
            }
    
            let min = SIMD3<Float>(x: minX, y: minY, z: minZ)
            let max = SIMD3<Float>(x: maxX, y: maxY, z: maxZ)
            let box = MDLAxisAlignedBoundingBox(maxBounds: max, minBounds: min)
    
            boundingBoxes.append(box)
        }
    
        return boundingBoxes
    }
    

    请注意,此函数希望子网格具有 32 位索引,尽管它也可以调整为支持 16 位索引。

    要驱动它,您还需要提供一个MDLVertexAttributeData 对象,该对象指向包含网格中的顶点数据。这样做的方法如下:

    let mesh = try! MTKMesh(mesh: mdlMesh, device: device)
    let positionAttrData = mdlMesh.vertexAttributeData(forAttributeNamed: MDLVertexAttributePosition, as: .float3)!
    let boundingBoxes = try? boundingBoxesForSubmeshes(of: mesh, positionAttributeData: positionAttrData)
    

    我还没有彻底测试过这段代码,但它似乎在我有限的一组测试用例中产生了合理的结果。使用调试网格可视化框应立即显示它们是否正确。

    【讨论】:

      猜你喜欢
      • 2016-07-01
      • 2011-07-23
      • 2017-07-10
      • 1970-01-01
      • 2013-01-10
      • 1970-01-01
      • 2018-08-17
      • 1970-01-01
      • 2016-12-21
      相关资源
      最近更新 更多