将屏幕外SCNScene渲染为UIImage [英] Render off-screen SCNScene into UIImage
问题描述
如何在 UIImage
中渲染屏幕外 SCNScene
?
我知道 SCNView
提供 -snapshot
方法,但不幸的是,这不适用于屏幕外的视图。 类似问题之前曾被问过答案建议使用 glReadPixels
从OpenGL读取位图数据,但这种方法对我的屏幕外场景不起作用。
I know that SCNView
provides a -snapshot
method, but unfortunately that doesn't work for off-screen views. A similar question have been asked before where one of the answers suggest reading the bitmap data from OpenGL using glReadPixels
, but that approach doesn't work for me with an off-screen scene.
我尝试使用 SCNRenderer
渲染到 GLKView
的上下文中,但没有成功。
I tried rendering into the context of an GLKView
using SCNRenderer
without success.
推荐答案
Swift 4与SCNRenderer:
你可以使用 SCNRenderer 的快照方法可以非常轻松地将屏幕外的SCNScene呈现给UIImage。
You can use SCNRenderer's snapshot method to render the off-screen SCNScene to a UIImage pretty easily.
这里有一些注意事项,它使用Metal。我不知道设备/ iOS版本的截止位置,但你需要一个更新的设备。您也无法在模拟器上运行它。
Some caveats here, this uses Metal. I don't know where the device/iOS version cutoff is, but you'll need a newer device. You also won't be able to run it on the simulator.
步骤1 - 像往常一样设置场景:
// Set up your scene which won't be displayed
let hiddenScene = SCNScene()
[insert code to set up your nodes, cameras, and lights here]
第2步 - 设置SCNRenderer - 渲染器在模拟器上将为零:
// Set up the renderer -- this returns nil on simulator
let renderer = SCNRenderer(device: MTLCreateSystemDefaultDevice(), options: nil)
renderer!.scene = hiddenScene
第3步 - 将场景渲染为UIImage:
// You can use zero for renderTime unless you are using animations,
// in which case, renderTime should be the current scene time.
let renderTime = TimeInterval(0)
// Output size
let size = CGSize(width:300, height: 150)
// Render the image
let image = renderer!.snapshot(atTime: renderTime, with: size,
antialiasingMode: SCNAntialiasingMode.multisampling4X)
如果您正在运行动画,则需要增加renderTime或将其设置为要渲染的时间索引。例如,如果要将帧渲染到场景中4秒,则将其设置为4.这仅影响动画 - 它不会回溯并显示场景的历史视图。
If you are running animations, you'll need to increment renderTime or set it to the time index you want to render. For example, if you want to render the frame 4 seconds into the scene, you would set it to 4. This only affects animations -- it won't go back in time and show you a historical view of your scene.
例如,如果您运行的是使用SCNNode.runAction运行动画,您可能希望每隔60秒(0.16667秒)继续递增renderTime,以便每当您决定渲染时,你有一个更新的renderTime:
For example, if you run are running animations with SCNNode.runAction, you may want to keep incrementing renderTime every 60th of a second (0.16667 seconds), so that whenever you decide to render, you've got an updated renderTime:
var timer : Timer
var renderTime = TimeInterval(0)
timer = Timer.scheduledTimer(withTimeInterval: 0.016667, repeats: true, block: { (t) in
self?.renderTime += 0.016667
}
})
使用 CADisplayLink 可能是更好的时机解决方案。
Using CADisplayLink is probably a better solution for the timing though.
这是一个非常快速和肮脏的实施示例。
Here's a very quick and dirty implementation example.
这篇关于将屏幕外SCNScene渲染为UIImage的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!