Как извлечь буфер глубины SceneKit во время выполнения в AR-сцене? - PullRequest
2 голосов
/ 30 апреля 2019

Как извлечь буфер глубины SceneKit? Я делаю приложение на основе AR, которое работает под управлением Metal, и я действительно изо всех сил пытаюсь найти какую-либо информацию о том, как извлечь буфер глубины 2D, чтобы я мог рендерить фантастические 3D фотографии моих сцен. Любая помощь с благодарностью.

1 Ответ

1 голос
/ 30 апреля 2019

Ваш вопрос неясен, но я постараюсь ответить.

Пропуск глубины из вида VR

Если вам нужно отрендерить проход глубины из 3D-среды SceneKit, то вы должны использовать дляНапример, структура SCNGeometrySource.Semantic .Существуют свойства типа vertex, normal, texcoord, color и tangent.Давайте посмотрим, что такое свойство типа vertex:

static let vertex: SCNGeometrySource.Semantic

Эта семантика идентифицирует данные, содержащие положения каждой вершины в геометрии.Для пользовательской шейдерной программы вы используете эту семантику, чтобы связать данные положения вершины SceneKit с входным атрибутом шейдера.Данные о положении вершины обычно представляют собой массив из трех- или четырехкомпонентных векторов.

Вот фрагмент кода из Образца глубины iOS проекта.

ОБНОВЛЕНО: Используя этот код, вы можете получить позицию для каждой точки в 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)
    }
}

Пропуск глубины из вида AR

Если вам необходимо выполнить рендеринг прохода глубины из ARSCNView, это возможно только в том случае, если вы используете ARFaceTrackingConfiguration для фронтальной камеры.Если это так, то вы можете использовать свойство экземпляра capturedDepthData , которое предоставляет вам карту глубины, захваченную вместе с видеокадром.

var capturedDepthData: AVDepthData? { get }

Но это изображение карты глубинына only 15 fps and of lower resolution, чем соответствующее RGB-изображение при 60 к / с .

В режиме 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 рамки.

Посмотрите на Карта глубины изображения учебник, где будет Диспаритет концепция будетпознакомил вас.

...