SKRenderer——奥秘class
SKRenderer -- the mystery class
在观看了 WWDC2017 的 session 609 视频后,我对从 SpriteKit 中提取屏幕外金属纹理大肆宣传。
这是一年多以前的事了!
然而 SKRenderer
上绝对没有概述文档,也没有示例代码。
https://developer.apple.com/documentation/spritekit/skrenderer
我觉得这确实很奇怪。 这里有人对此 class、它的文档或示例代码有任何见解吗?
顺便说一句,SKTransformNode
也是如此。
SKRenderer
的基本用法非常简单,但有一些奇怪之处使其在实践中有些古怪。
首先,基础知识。要实例化渲染器,请使用 rendererWithDevice:
方法。这个方法取一个id<MTLDevice>
,比如系统默认的设备。原谅了Objective-C;这将很容易地转换为 Swift:
SKRenderer *renderer = [SKRenderer rendererWithDevice:mtlDevice];
为了告诉渲染器要绘制什么,我们将其与先前创建的场景相关联:
renderer.scene = (SKScene *)scene;
如果您想要 运行 的操作,您需要手动取消暂停场景,这通常由 SKView
在呈现场景时完成:
scene.paused = NO;
要实际绘制场景,我们需要提供命令缓冲区和渲染通道描述符。假设您正在使用 MTKView
来处理 运行 显示 link 计时器并管理 CAMetalLayer
,您可以编写这样的委托方法,它会更新场景的时间(和动作)通过渲染器,然后绘制到 MTKView
的可绘制对象中:
- (void)drawInMTKView:(nonnull MTKView *)view {
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
if (renderPassDescriptor == nil) {
return;
}
[self.renderer updateAtTime:CACurrentMediaTime()];
id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer];
CGRect viewport = CGRectMake(0, 0, view.drawableSize.width, view.drawableSize.height);
[self.renderer renderWithViewport:viewport
commandBuffer:commandBuffer
renderPassDescriptor:renderPassDescriptor];
// TODO: Add any additional Metal rendering here
[commandBuffer presentDrawable:view.currentDrawable];
[commandBuffer commit];
}
如果您使用此技术,请记住将 MTKView
的 framebufferOnly
属性 设置为 NO
。
如果您想将屏幕外渲染到您创建的纹理中,您将需要做更多的手动工作,但所涉及的概念是相同的。您可以通过创建额外的渲染通道 descriptors/encoders 对渲染到同一纹理的单独通道进行编码;请记住将原色附件的 loadAction
设置为 MTLLoadActionLoad
以保留整个过程中的纹理内容。
您还可以使用 renderWithViewport:renderCommandEncoder:renderPassDescriptor:commandQueue:
将所有绘图合并到一个过程中。
一些注意事项:
- 据我所知,
viewport
参数被忽略了。
- 如果您希望
SKScene
接收NSResponder
动作,您需要手动转发它们或将场景插入响应链。这尤其适用于关键事件,其中场景(或负责转发给它的对象)需要第一个响应者。
- None 用于转换触摸或鼠标事件位置的便捷方法将在
SKView
未呈现场景时起作用;您需要进行一些手动翻译。
swift
func render(renderCommandEncoder: MTLRenderCommandEncoder){
skScene.size = Engine.previewViewSize
currentTime = 0//allows looping skaction
//sprite kit render
skrender.update(atTime: currentTime )
let viewport = CGRect(x: 0, y: 0, width: (Engine.previewViewSize.width), height: (Engine.previewViewSize.height))
skScene.isPaused = false
skrender.scene = skScene
skrender.render(withViewport: viewport, renderCommandEncoder: renderCommandEncoder, renderPassDescriptor: Engine.currentRenderPassDescriptor, commandQueue: Engine.CommandQueue)
}
在观看了 WWDC2017 的 session 609 视频后,我对从 SpriteKit 中提取屏幕外金属纹理大肆宣传。
这是一年多以前的事了!
然而 SKRenderer
上绝对没有概述文档,也没有示例代码。
https://developer.apple.com/documentation/spritekit/skrenderer
我觉得这确实很奇怪。 这里有人对此 class、它的文档或示例代码有任何见解吗?
顺便说一句,SKTransformNode
也是如此。
SKRenderer
的基本用法非常简单,但有一些奇怪之处使其在实践中有些古怪。
首先,基础知识。要实例化渲染器,请使用 rendererWithDevice:
方法。这个方法取一个id<MTLDevice>
,比如系统默认的设备。原谅了Objective-C;这将很容易地转换为 Swift:
SKRenderer *renderer = [SKRenderer rendererWithDevice:mtlDevice];
为了告诉渲染器要绘制什么,我们将其与先前创建的场景相关联:
renderer.scene = (SKScene *)scene;
如果您想要 运行 的操作,您需要手动取消暂停场景,这通常由 SKView
在呈现场景时完成:
scene.paused = NO;
要实际绘制场景,我们需要提供命令缓冲区和渲染通道描述符。假设您正在使用 MTKView
来处理 运行 显示 link 计时器并管理 CAMetalLayer
,您可以编写这样的委托方法,它会更新场景的时间(和动作)通过渲染器,然后绘制到 MTKView
的可绘制对象中:
- (void)drawInMTKView:(nonnull MTKView *)view {
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
if (renderPassDescriptor == nil) {
return;
}
[self.renderer updateAtTime:CACurrentMediaTime()];
id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer];
CGRect viewport = CGRectMake(0, 0, view.drawableSize.width, view.drawableSize.height);
[self.renderer renderWithViewport:viewport
commandBuffer:commandBuffer
renderPassDescriptor:renderPassDescriptor];
// TODO: Add any additional Metal rendering here
[commandBuffer presentDrawable:view.currentDrawable];
[commandBuffer commit];
}
如果您使用此技术,请记住将 MTKView
的 framebufferOnly
属性 设置为 NO
。
如果您想将屏幕外渲染到您创建的纹理中,您将需要做更多的手动工作,但所涉及的概念是相同的。您可以通过创建额外的渲染通道 descriptors/encoders 对渲染到同一纹理的单独通道进行编码;请记住将原色附件的 loadAction
设置为 MTLLoadActionLoad
以保留整个过程中的纹理内容。
您还可以使用 renderWithViewport:renderCommandEncoder:renderPassDescriptor:commandQueue:
将所有绘图合并到一个过程中。
一些注意事项:
- 据我所知,
viewport
参数被忽略了。 - 如果您希望
SKScene
接收NSResponder
动作,您需要手动转发它们或将场景插入响应链。这尤其适用于关键事件,其中场景(或负责转发给它的对象)需要第一个响应者。 - None 用于转换触摸或鼠标事件位置的便捷方法将在
SKView
未呈现场景时起作用;您需要进行一些手动翻译。
swift
func render(renderCommandEncoder: MTLRenderCommandEncoder){
skScene.size = Engine.previewViewSize
currentTime = 0//allows looping skaction
//sprite kit render
skrender.update(atTime: currentTime )
let viewport = CGRect(x: 0, y: 0, width: (Engine.previewViewSize.width), height: (Engine.previewViewSize.height))
skScene.isPaused = false
skrender.scene = skScene
skrender.render(withViewport: viewport, renderCommandEncoder: renderCommandEncoder, renderPassDescriptor: Engine.currentRenderPassDescriptor, commandQueue: Engine.CommandQueue)
}