Вот функция, которая принимает 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)
Я не тестировал этот код полностью, но, похоже, он дает нормальные результаты в моем ограниченном наборе тестовых случаев. Визуализация блоков с сеткой отладки должна сразу показать, верны они или нет.