** Внимание! Это может быть не подходящий метод для App Store. Но он работает.
Шаг 1: Поменяйте метод nextDrawable CAMetalLayer на новый, используя swizzling. Сохраните CAMetalDrawable для каждого цикла визуализации.
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: Настройте swizzling в AppDelegate: didFinishLaunchingWithOptions
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
CAMetalLayer.setupSwizzling()
return true
}
Шаг 3: Отключить framebufferOnly для CAMetalLayer вашего в SCNView (в Чтобы позвонить GetBytes для MTLTexture)
if let metalLayer = scnView.layer as? CAMetalLayer {
metalLayer.framebufferOnly = false
}
Шаг 4: В своем делегате SCNView (SCNSceneRendererDelegate), играйте с t exture
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 в то же время)
Основываясь на том, что он говорит здесь, https://developer.apple.com/reference/metal/mtlrenderpassattachdesdescriptor, вам необходимо создать новый MTLRenderPassDescriptor, получить MTLRenderPassAttachmentDescriptor и установить MTLTexture в качестве своей цели рендеринга. Учитывая то, что у вас есть, например MTLRenderCommandEncoder, кажется, что они сделали доступным для вас рисование, а не захватить буфер. Если вы можете создать свой собственный MTLRenderPassDescriptor и дать это SCNView, вы можете установить цель рендеринга. –
О, похоже, вы можете установить свой собственный MTLRenderPassDescriptor с помощью SCNRenderer https://developer.apple.com/reference/scenekit/scnrenderer. Это, вероятно, то, что вам нужно сделать. –
Настройка SCNRenderer заставляет его повторно отображать сцену (так как она находится в собственном цикле рендеринга), что приводит к снижению производительности. Я надеялся просто захватить базовую текстуру из уже визуализированной сцены (предполагая, что SCNView отображает один, что, похоже, имеет место, поскольку в качестве слоя поддержки для представления используется CAMetalLayer). –