对于任何在七年后查看此线程的人,我尝试使用上述方法,但效果相对较慢。我想要将整个SKScene渲染到屏幕外,因为我正在以帧为单位生成视频中的图像。这意味着我不能使用LearnCocos2D建议的第一种方法,因为它需要在屏幕上绘制视图,而第二种方法需要很长时间将SKTexture转换为UIImage。您可以使用iOS 11.0中引入的新的SKRenderer类将整个场景渲染到UIImage,并利用Metal使渲染速度相对较快。我能够在大约0.013秒内呈现1920x1080的SKScene!
您可以使用以下扩展:
- 确保导入MetalKit
- ignoreScreenScale参数指定输出图像是否应该是像素精确的。通常,如果您将在屏幕上显示图像,则希望其值为false。当ignoreScreenScale为false时,输出图像的大小按设备比例进行缩放,使场景上的每个“点”在图像上占据的像素数与在屏幕上一样。当ignoreScreenScale为true时,输出图像的像素大小等于点数大小的SKScene。
干杯!
extension SKScene {
func toImage(ignoreScreenScale: Bool = false) -> UIImage? {
guard let device = MTLCreateSystemDefaultDevice(),
let commandQueue = device.makeCommandQueue(),
let commandBuffer = commandQueue.makeCommandBuffer() else { return nil }
let scale = ignoreScreenScale ? 1 : UIScreen.main.scale
let size = self.size.applying(CGAffineTransform(scaleX: scale, y: scale))
let renderer = SKRenderer(device: device)
let renderPassDescriptor = MTLRenderPassDescriptor()
var r = CGFloat.zero, g = CGFloat.zero, b = CGFloat.zero, a = CGFloat.zero
backgroundColor.getRed(&r, green: &g, blue: &b, alpha: &a)
let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.usage = [.renderTarget, .shaderRead]
textureDescriptor.width = Int(size.width)
textureDescriptor.height = Int(size.height)
let texture = device.makeTexture(descriptor: textureDescriptor)
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].texture = texture
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
red: Double(r),
green: Double(g),
blue: Double(b),
alpha:Double(a)
)
renderer.scene = self
renderer.render(withViewport: CGRect(origin: .zero, size: size), commandBuffer: commandBuffer, renderPassDescriptor: renderPassDescriptor)
commandBuffer.commit()
let image = CIImage(mtlTexture: texture!, options: nil)!
let transformed = image.transformed(by: CGAffineTransform(scaleX: 1, y: -1).translatedBy(x: 0, y: -image.extent.size.height))
return UIImage(ciImage: transformed)
}
}