Захват ARSCNView с виртуальными объектами - iOS - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть ARSCNView с нарисованными виртуальными объектами. Виртуальные объекты нарисованы на лице пользователя. Сеанс имеет следующую конфигурацию:

let configuration = ARFaceTrackingConfiguration()
configuration.worldAlignment = .gravityAndHeading

sceneView.session.run(configuration)

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

 public func session(_ session: ARSession, didUpdate frame: ARFrame) {
    videoSource.sendBuffer(frame.capturedImage, timestamp: frame.timestamp)
 }

Виртуальные объекты не будут показаны моему абоненту.

Одна из попыток - не полагаться на обратный вызов ARSessionDelegate, а использовать DispatchSourceTimer для отправки событий.

func startCaptureView() {  
  // Timer with 0.1 second interval
  timer.schedule(deadline: .now(), repeating: .milliseconds(100))
  timer.setEventHandler { [weak self] in
    // Turn sceneView data into UIImage
    guard let sceneImage: CGImage = self?.sceneView.snapshot().cgImage else {
      return
    }

    self?.videoSourceQueue.async { [weak self] in
       if let buffer: CVPixelBuffer = ImageProcessor.pixelBuffer(forImage: sceneImage) {
             self?.videoSource.sendBuffer(buffer, timestamp: Double(mach_absolute_time()))
        }
    }
  }

  timer.resume()
}

Вызывающий медленно получает данные с прерывистым видео опыт и изображения имеют неправильный размер.

Есть предложения о том, как отправить данные о виртуальном объекте вместе с захваченным кадром?

Ссылка: https://medium.com/agora-io/augmented-reality-video-conference-6845c001aec0

1 Ответ

2 голосов
/ 20 апреля 2020

Причина, по которой виртуальные объекты не отображаются, заключается в том, что ARKit предоставляет только необработанное изображение, поэтому frame.capturedImage - это изображение, снятое камерой, без какой-либо визуализации SceneKit. Чтобы передать отрендеренное видео, вам нужно реализовать внеэкранный SCNRenderer и передать пиксельный буфер в SDK Agora.

Я бы порекомендовал вам ознакомиться с платформой с открытым исходным кодом AgoraARKit . Я написал фреймворк, и он реализует Agora.io Video SDK и ARVideoKit в качестве зависимостей. ARVideoKit - это популярная библиотека, которая реализует внеэкранный рендерер и предоставляет буфер визуализированных пикселей.

В библиотеке реализован WorldTracking по умолчанию. Если вы хотите расширить класс ARBroadcaster для реализации FaceTracking, вы можете использовать этот код:

import ARKit

class FaceBroadcaster : ARBroadcaster {

    // placements dictionary
    var faceNodes: [UUID:SCNNode] = [:]           // Dictionary of faces

    override func viewDidLoad() {
        super.viewDidLoad() 
    }

    override func setARConfiguration() {
        print("setARConfiguration")        // Configure ARKit Session
        let configuration = ARFaceTrackingConfiguration()
        configuration.isLightEstimationEnabled = true
        // run the config to start the ARSession
        self.sceneView.session.run(configuration)
        self.arvkRenderer?.prepare(configuration)
    }

    // anchor detection
    override func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        super.renderer(renderer, didAdd: node, for: anchor)
        guard let sceneView = renderer as? ARSCNView, anchor is ARFaceAnchor else { return }
        /*
         Write depth but not color and render before other objects.
         This causes the geometry to occlude other SceneKit content
         while showing the camera view beneath, creating the illusion
         that real-world faces are obscuring virtual 3D objects.
         */
        let faceGeometry = ARSCNFaceGeometry(device: sceneView.device!)!
        faceGeometry.firstMaterial!.colorBufferWriteMask = []
        let occlusionNode = SCNNode(geometry: faceGeometry)
        occlusionNode.renderingOrder = -1

        let contentNode = SCNNode()
        contentNode.addChildNode(occlusionNode)
        node.addChildNode(contentNode)
        faceNodes[anchor.identifier] = node
    }
}
...