【发布时间】:2020-12-23 06:51:59
【问题描述】:
这个问题在某种程度上建立在this 帖子上,其中的想法是从带有激光雷达扫描仪的 iOS 设备中获取ARMeshGeometry,计算纹理坐标,并将采样的相机帧应用为给定网格的纹理,从而允许用户创建其环境的“逼真的”3D 表示。
根据那篇帖子,我已经调整了其中一个响应来计算纹理坐标,就像这样;
func buildGeometry(meshAnchor: ARMeshAnchor, arFrame: ARFrame) -> SCNGeometry {
let vertices = meshAnchor.geometry.vertices
let faces = meshAnchor.geometry.faces
let camera = arFrame.camera
let size = arFrame.camera.imageResolution
// use the MTL buffer that ARKit gives us
let vertexSource = SCNGeometrySource(buffer: vertices.buffer, vertexFormat: vertices.format, semantic: .vertex, vertexCount: vertices.count, dataOffset: vertices.offset, dataStride: vertices.stride)
// set the camera matrix
let modelMatrix = meshAnchor.transform
var textCords = [CGPoint]()
for index in 0..<vertices.count {
let vertexPointer = vertices.buffer.contents().advanced(by: vertices.offset + vertices.stride * index)
let vertex = vertexPointer.assumingMemoryBound(to: (Float, Float, Float).self).pointee
let vertex4 = SIMD4<Float>(vertex.0, vertex.1, vertex.2, 1)
let world_vertex4 = simd_mul(modelMatrix, vertex4)
let world_vector3 = simd_float3(x: world_vertex4.x, y: world_vertex4.y, z: world_vertex4.z)
let pt = camera.projectPoint(world_vector3, orientation: .portrait, viewportSize: CGSize(width: CGFloat(size.height), height: CGFloat(size.width)))
let v = 1.0 - Float(pt.x) / Float(size.height)
let u = Float(pt.y) / Float(size.width)
//let z = vector_float2(u, v)
let c = CGPoint(x: v, y: u)
textCords.append(c)
}
// Setup the texture coordinates
let textureSource = SCNGeometrySource(textureCoordinates: textCords)
// Setup the normals
let normalsSource = SCNGeometrySource(meshAnchor.geometry.normals, semantic: .normal)
// Setup the geometry
let faceData = Data(bytesNoCopy: faces.buffer.contents(), count: faces.buffer.length, deallocator: .none)
let geometryElement = SCNGeometryElement(data: faceData, primitiveType: .triangles, primitiveCount: faces.count, bytesPerIndex: faces.bytesPerIndex)
let nodeGeometry = SCNGeometry(sources: [vertexSource, textureSource, normalsSource], elements: [geometryElement])
/* Setup texture - THIS IS WHERE I AM STUCK
let texture = textureConverter.makeTextureForMeshModel(frame: arFrame)
*/
let imageMaterial = SCNMaterial()
imageMaterial.isDoubleSided = false
imageMaterial.diffuse.contents = texture!
nodeGeometry.materials = [imageMaterial]
return nodeGeometry
}
我正在努力确定这些纹理坐标是否实际计算正确,以及随后如何对相机帧进行采样以将相关帧图像应用为该网格的纹理。
链接的问题表明将ARFrame 的capturedImage(这是CVPixelBuffer)属性转换为MTLTexture 将是实时性能的理想选择,但对我来说很明显CVPixelBuffer 是YCbCr 图像,而我相信我需要RGB 图像。
在我的textureConverter 类中,我试图将CVPixelBuffer 转换为MTLTexture,但我不确定如何返回RGB MTLTexture;
func makeTextureForMeshModel(frame: ARFrame) -> MTLTexture? {
if CVPixelBufferGetPlaneCount(frame.capturedImage) < 2 {
return nil
}
let cameraImageTextureY = createTexture(fromPixelBuffer: frame.capturedImage, pixelFormat: .r8Unorm, planeIndex: 0)
let cameraImageTextureCbCr = createTexture(fromPixelBuffer: frame.capturedImage, pixelFormat: .rg8Unorm, planeIndex: 1)
/* How do I blend the Y and CbCr textures, or return a RGB texture, to return a single MTLTexture?
return ...
}
func createTexture(fromPixelBuffer pixelBuffer: CVPixelBuffer, pixelFormat: MTLPixelFormat, planeIndex: Int) -> CVMetalTexture? {
let width = CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex)
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, planeIndex)
var texture: CVMetalTexture? = nil
let status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, pixelBuffer, nil, pixelFormat,
width, height, planeIndex, &texture)
if status != kCVReturnSuccess {
texture = nil
}
return texture
}
最后,我不完全确定我是否真的需要 RGB 纹理与 YCbCr 纹理,但我仍然不确定如何返回正确的图像纹理(我尝试只返回 CVPixelBuffer 而不必担心 YCbCr 色彩空间,通过手动设置纹理格式,结果是一个非常奇怪的图像)。
【问题讨论】:
-
你发现了吗?
-
我自己没有测试过,但这可能值得检查:stackoverflow.com/questions/61538799/…
-
嘿,如果你愿意,你可以看看我的 3D 扫描项目的一部分。我已将相关文件放在 github 上:MetalScanDemo。它在扫描时渲染没有纹理的网格(只有蓝色三角形),但是当完成扫描时,它会从保存的相机图像中创建一个带纹理的网格并将其放置在您面前。可能对您的情况有用!
-
@beatTheSystem42 干得好!你有一个完整的项目可以发布到 github 等吗?我收到
Cannot find Colors() in scope错误。许多交易,快速的菜鸟。 -
@lewis 当然,看看我刚刚发布的答案
标签: scenekit arkit metal metalkit