如何提取SceneKit深度缓冲区?我制作了一个运行Metal的基于AR的应用程序,我真的很难找到有关如何提取2D深度缓冲区的任何信息,以便可以渲染场景中精美的3D照片。任何帮助表示赞赏。
答案 0 :(得分:1)
您的问题尚不清楚,但我会尽力回答。
如果需要从SceneKit的3D环境渲染深度传递,则应使用SCNGeometrySource.Semantic结构。有vertex
,normal
,texcoord
,color
和tangent
类型属性。让我们看看vertex
类型的属性是什么
static let vertex: SCNGeometrySource.Semantic
此语义标识包含几何中每个顶点位置的数据。对于自定义着色器程序,您可以使用此语义将SceneKit的顶点位置数据绑定到着色器的输入属性。顶点位置数据通常是由三个或四个分量向量组成的数组。
这是iOS Depth Sample项目中的代码摘录。
更新:使用此代码,您可以为SCNScene中的每个点获取位置,并为这些点分配颜色(这就是zDepth通道的真正含义):
import SceneKit
struct PointCloudVertex {
var x: Float, y: Float, z: Float
var r: Float, g: Float, b: Float
}
@objc class PointCloud: NSObject {
var pointCloud : [SCNVector3] = []
var colors: [UInt8] = []
public func pointCloudNode() -> SCNNode {
let points = self.pointCloud
var vertices = Array(repeating: PointCloudVertex(x: 0,
y: 0,
z: 0,
r: 0,
g: 0,
b: 0),
count: points.count)
for i in 0...(points.count-1) {
let p = points[i]
vertices[i].x = Float(p.x)
vertices[i].y = Float(p.y)
vertices[i].z = Float(p.z)
vertices[i].r = Float(colors[i * 4]) / 255.0
vertices[i].g = Float(colors[i * 4 + 1]) / 255.0
vertices[i].b = Float(colors[i * 4 + 2]) / 255.0
}
let node = buildNode(points: vertices)
return node
}
private func buildNode(points: [PointCloudVertex]) -> SCNNode {
let vertexData = NSData(
bytes: points,
length: MemoryLayout<PointCloudVertex>.size * points.count
)
let positionSource = SCNGeometrySource(
data: vertexData as Data,
semantic: SCNGeometrySource.Semantic.vertex,
vectorCount: points.count,
usesFloatComponents: true,
componentsPerVector: 3,
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: 0,
dataStride: MemoryLayout<PointCloudVertex>.size
)
let colorSource = SCNGeometrySource(
data: vertexData as Data,
semantic: SCNGeometrySource.Semantic.color,
vectorCount: points.count,
usesFloatComponents: true,
componentsPerVector: 3,
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: MemoryLayout<Float>.size * 3,
dataStride: MemoryLayout<PointCloudVertex>.size
)
let element = SCNGeometryElement(
data: nil,
primitiveType: .point,
primitiveCount: points.count,
bytesPerIndex: MemoryLayout<Int>.size
)
element.pointSize = 1
element.minimumPointScreenSpaceRadius = 1
element.maximumPointScreenSpaceRadius = 5
let pointsGeometry = SCNGeometry(sources: [positionSource, colorSource], elements: [element])
return SCNNode(geometry: pointsGeometry)
}
}
如果您需要从ARSCNView渲染深度通道,则只有在您将ARFaceTrackingConfiguration用于前置摄像头的情况下才有可能。如果是这样,则可以使用capturedDepthData实例属性,该属性为您带来与视频帧一起捕获的深度图。
var capturedDepthData: AVDepthData? { get }
但是此深度图图像比60 fps的相应RGB图像高only 15 fps and of lower resolution
。
基于面部的AR在兼容设备上使用前置的深度感应摄像头。在运行这种配置时,会话所售出的帧除了包含由彩色相机捕获的彩色像素缓冲区(请参见capturedImage)外,还包含由深度相机捕获的深度图。运行其他AR配置时,此属性的值始终为零。
真实的代码可能是这样的:
extension ViewController: ARSCNViewDelegate {
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
DispatchQueue.global().async {
guard let frame = self.sceneView.session.currentFrame else {
return
}
if let depthImage = frame.capturedDepthData {
self.depthImage = (depthImage as! CVImageBuffer)
}
}
}
}
此外,您可以使用2个后置摄像头和AVFoundation
框架来提取真实的深度传递。
请参阅Image Depth Map教程,其中将向您介绍差异概念。