SceneKit-从SCNView作为MTLTexture获取渲染的场景,而无需使用单独的SCNRenderer [英] SceneKit - Get the rendered scene from a SCNView as a MTLTexture without using a separate SCNRenderer

查看:177
本文介绍了SceneKit-从SCNView作为MTLTexture获取渲染的场景,而无需使用单独的SCNRenderer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 SCNView 使用的是Metal作为渲染API,我想知道是否有一种方法可以将渲染的场景作为 MTLTexture 来捕获,而不必使用单独的 SCNRenderer ?当我尝试通过 SCNView 显示场景并通过 SCNRenderer 将场景从屏幕外重新渲染为 MTLTexture 时,性能会下降.我正在尝试每帧抓取输出.)

My SCNView is using Metal as the rendering API and I would like to know if there's a way to grab the rendered scene as a MTLTexture without having to use a separate SCNRenderer? Performance drops when I'm trying to both display the scene via the SCNView and re-rendering the scene offscreen to a MTLTexture via a SCNRenderer (I'm trying to grab the output every frame).

SCNView ,我可以访问它使用的 MTLDevice MTLRenderCommandEncoder MTLCommandQueue ,但不能访问为了获得 MTLTexture (通过renderPassDescriptor.colorAttachments[0].texture)

SCNView gives me access to the MTLDevice, MTLRenderCommandEncoder, and MTLCommandQueue that it uses, but not to the underlying MTLRenderPassDescriptor that I would need in order to get the MTLTexture (via renderPassDescriptor.colorAttachments[0].texture)

我尝试过的一些替代方法是尝试使用SCNView.snapshot()来获取UIImage并将其转换,但性能甚至更差.

Some alternatives I tried was trying to use SCNView.snapshot() to get a UIImage and converting it but performance was even worse.

推荐答案

**警告:这可能不是App Store的正确方法.但是它正在工作.

** Warning: This may not be a proper method for App Store. But it's working.

第1步:使用swizzling将CAMetalLayer的nextDrawable方法替换为新方法. 为每个渲染循环保存CAMetalDrawable.

Step 1: Swap the method of nextDrawable of CAMetalLayer with a new one using swizzling. Save the CAMetalDrawable for each render loop.

extension CAMetalLayer {
  public static func setupSwizzling() {
    struct Static {
      static var token: dispatch_once_t = 0
    }

    dispatch_once(&Static.token) {
      let copiedOriginalSelector = #selector(CAMetalLayer.orginalNextDrawable)
      let originalSelector = #selector(CAMetalLayer.nextDrawable)
      let swizzledSelector = #selector(CAMetalLayer.newNextDrawable)

      let copiedOriginalMethod = class_getInstanceMethod(self, copiedOriginalSelector)
      let originalMethod = class_getInstanceMethod(self, originalSelector)
      let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

      let oldImp = method_getImplementation(originalMethod)
      method_setImplementation(copiedOriginalMethod, oldImp)
      method_exchangeImplementations(originalMethod, swizzledMethod)
    }
  }


  func newNextDrawable() -> CAMetalDrawable? {
    let drawable = orginalNextDrawable()
    // Save the drawable to any where you want
    AppManager.sharedInstance.currentSceneDrawable = drawable
    return drawable
  }

  func orginalNextDrawable() -> CAMetalDrawable? {
    // This is just a placeholder. Implementation will be replaced with nextDrawable.
    return nil
  }
}

第2步: 在AppDelegate中设置选项:didFinishLaunchingWithOptions

Step 2: Setup the swizzling in AppDelegate: didFinishLaunchingWithOptions

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  CAMetalLayer.setupSwizzling()
  return true
}

第3步: 仅为您的SCNView的CAMetalLayer禁用framebuffer(以便为MTLTexture调用getBytes)

Step 3: Disable framebufferOnly for your's SCNView's CAMetalLayer (In order to call getBytes for MTLTexture)

if let metalLayer = scnView.layer as? CAMetalLayer {
  metalLayer.framebufferOnly = false
}

第4步: 在您的SCNView的委托(SCNSceneRendererDelegate)中,使用纹理

Step 4: In your SCNView's delegate (SCNSceneRendererDelegate), play with the texture

func renderer(renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: NSTimeInterval) {
    if let texture = AppManager.sharedInstance.currentSceneDrawable?.texture where !texture.framebufferOnly {
      AppManager.sharedInstance.currentSceneDrawable = nil
      // Play with the texture
    }
}

第5步(可选): 您可能需要在获得的CAMetalLayer上确认可绘制对象是您的目标. (如果同时有一个以上的CAMetalLayer)

Step 5 (Optional): You may need to confirm the drawable at CAMetalLayer you are getting is your target. (If more then one CAMetalLayer at the same time)

这篇关于SceneKit-从SCNView作为MTLTexture获取渲染的场景,而无需使用单独的SCNRenderer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆