Я успешно интегрировал функцию отслеживания целевых изображений 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
перезаписывают буфера друг друга.
Что мне здесь не хватает?