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];
}

如果您使用此技术,请记住将 MTKViewframebufferOnly 属性 设置为 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)


}