如何将SCNRenderer与现有的MTLCommandBuffer结合起来?

Mat*_*tič 7 opengl-es scenekit vuforia swift metal

我通过将SDK提供的OpenGL上下文()与SceneKit的实例相结合,成功地将Vuforia SDK图像目标跟踪功能集成到iOS项目中.这使我能够利用SceneKit 3D API的简单性,同时受益于Vuforia的高精度图像检测.现在,我想通过用Metal替换OpenGL来做同样的事情.EAGLContextSCNRenderer

一些背景故事

我能够使用OpenGL在Vuforia绘制的实时视频纹理之上绘制SceneKit对象,而不会出现重大问题.

这是我在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())
}
Run Code Online (Sandbox Code Playgroud)

Apple在iOS 12上弃用了OpenGL

Apple宣布它在iOS 12上弃用OpenGL以来,我认为尝试迁移这个项目来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)
}
Run Code Online (Sandbox Code Playgroud)

我尝试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];
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,我只看到SCNRenderer OR结果的结果encoder,但从不在同一视图中.

在我看来,好像编码通过上面,并且SCNRenderer.render,正在覆盖彼此的缓冲区.

我在这里错过了什么?

小智 0

我想我已经找到答案了。我在endEncoding之后渲染scnrenderer,但我正在创建一个新的描述符。

    // Pass Metal context data to Vuforia Engine (we may have changed the encoder since
    // calling Vuforia::Renderer::begin)
    finishRender(UnsafeMutableRawPointer(Unmanaged.passRetained(drawable!.texture).toOpaque()), UnsafeMutableRawPointer(Unmanaged.passRetained(encoder!).toOpaque()))
    
    // ========== Finish Metal rendering ==========
    encoder?.endEncoding()
    
    // Commit the rendering commands
    // Command completed handler
    commandBuffer?.addCompletedHandler { _ in self.mCommandExecutingSemaphore.signal()}
    let screenSize = UIScreen.main.bounds.size
    let newDescriptor = MTLRenderPassDescriptor()
    
    // Draw to the drawable's texture
    newDescriptor.colorAttachments[0].texture = drawable?.texture

    // Store the data in the texture when rendering is complete
    newDescriptor.colorAttachments[0].storeAction = MTLStoreAction.store
    // Use textureDepth for depth operations.
    newDescriptor.depthAttachment.texture = mDepthTexture;
    renderer?.render(atTime: 0, viewport: CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height), commandBuffer: commandBuffer!, passDescriptor: newDescriptor)
    
    // Present the drawable when the command buffer has been executed (Metal
    // calls to CoreAnimation to tell it to put the texture on the display when
    // the rendering is complete)
    commandBuffer?.present(drawable!)
    
    // Commit the command buffer for execution as soon as possible
    commandBuffer?.commit()
Run Code Online (Sandbox Code Playgroud)