Как объединить SCNRenderer с существующим MTLCommandBuffer? - PullRequest
0 голосов
/ 26 августа 2018

Я успешно интегрировал функцию отслеживания целевых изображений Vuforia SDK в проект iOS, объединив контекст OpenGL (EAGLContext), который предоставляет SDK, с экземпляром SceneKit SCNRenderer. Это позволило мне использовать простоту 3D API SceneKit и в то же время извлечь выгоду из высокоточного распознавания изображений Vuforia. Теперь я хотел бы сделать то же самое, заменив OpenGL на Metal.

Немного предыстории

Мне удалось нарисовать объекты SceneKit поверх текстуры живого видео, нарисованной Vuforia, используя OpenGL без особых проблем.

Вот упрощенная настройка, которую я использовал с OpenGL :

func configureRenderer(for context: EAGLContext) {
    self.renderer = SCNRenderer(context: context, options: nil)
    self.scene = SCNScene()
    renderer.scene = scene

    // other scenekit setup
}

func render() {
    // manipulate scenekit nodes

    renderer.render(atTime: CFAbsoluteTimeGetCurrent())
}

Apple не поддерживает OpenGL на iOS 12

Поскольку Apple объявила, что она устарела в OpenGL на iOS 12 , я подумал, что было бы неплохо попытаться перенести этот проект на использование Metal вместо OpenGL.

Теоретически это должно быть просто, поскольку Vuforia поддерживает Metal из коробки. Однако, пытаясь интегрировать его, я врезался в стену.

Вопрос

Представление, кажется, когда-либо отображает только результаты рендерера SceneKit или текстур, закодированных Vuforia, но никогда не одновременно. Это зависит от того, что кодируется первым. Что мне нужно сделать, чтобы смешать оба результата вместе?

Вот в двух словах проблемная настройка:

func configureRenderer(for device: MTLDevice) {
    let renderer = SCNRenderer(device: device, options: nil)
    self.scene = SCNScene()
    renderer.scene = scene

    // other scenekit setup
}

func render(viewport: CGRect, commandBuffer: MTLCommandBuffer, drawable: CAMetalDrawable) {
    // manipulate scenekit nodes

    let renderPassDescriptor = MTLRenderPassDescriptor()
    renderPassDescriptor.colorAttachments[0].texture = drawable.texture
    renderPassDescriptor.colorAttachments[0].loadAction = .load
    renderPassDescriptor.colorAttachments[0].storeAction = .store
    renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0, blue: 0, alpha: 0)

    renderer!.render(withViewport: viewport, commandBuffer: commandBuffer, passDescriptor: renderPassDescriptor)
}

Я пытался дозвониться до render либо после encoder.endEncoding, либо до commandBuffer.renderCommandEncoderWithDescriptor:

metalDevice = MTLCreateSystemDefaultDevice();
metalCommandQueue = [metalDevice newCommandQueue];
id<MTLCommandBuffer>commandBuffer = [metalCommandQueue commandBuffer];

//// -----> call the `render(viewport:commandBuffer:drawable) here <------- \\\\

id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];

// calls to encoder to render textures from Vuforia

[encoder endEncoding];

//// -----> or here <------- \\\\

[commandBuffer presentDrawable:drawable];
[commandBuffer commit];

В любом случае я вижу только результаты SCNRenderer ИЛИ результатов encoder, но никогда оба в одном и том же виде.

Мне кажется, что кодирование выше и SCNRenderer.render перезаписывают буфера друг друга.

Что мне здесь не хватает?

...