** A warning. This may not be the right method for the App Store. But it works.
Step 1: replace the nextDrawable CAMetalLayer method with a new one using swizzling. Save the CAMetalDrawable for each render cycle.
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()
Step 2: Configure swizzling in AppDelegate: didFinishLaunchingWithOptions
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { CAMetalLayer.setupSwizzling() return true }
Step 3: Disable framebufferOnly for your SCNView CAMetalLayer (to call getBytes for MTLTexture)
if let metalLayer = scnView.layer as? CAMetalLayer { metalLayer.framebufferOnly = false }
Step 4: In your SCNView 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
Step 5 (optional): You may need to confirm that the one you select on the CAMetalLayer you receive is your goal. (If more than one CAMetalLayer at a time)
source share