Найти ограничивающую рамку вложенной сети в iOS - PullRequest
1 голос
/ 25 июня 2019

Я рисую 3D-модель, как показано ниже, из файла obj.Мне нужно найти граничную рамку для каждой вложенной сетки этого файла 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.

1 Ответ

1 голос
/ 25 июня 2019

Вот функция, которая принимает MTKMesh и создает массив MDLAxisAlignedBoundingBox es в пространстве модели :

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)

Я не тестировал этот код полностью, но, похоже, он дает нормальные результаты в моем ограниченном наборе тестовых случаев. Визуализация блоков с сеткой отладки должна сразу показать, верны они или нет.

...