将屏幕外SCNScene渲染为UIImage [英] Render off-screen SCNScene into UIImage

查看:105
本文介绍了将屏幕外SCNScene渲染为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屋!

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