将纯 Metal-API 与 SceneKit 或 SpriteKit 一起使用

Posted

技术标签:

【中文标题】将纯 Metal-API 与 SceneKit 或 SpriteKit 一起使用【英文标题】:using the pure Metal-API alongside with SceneKit or SpriteKit 【发布时间】:2016-02-17 13:39:36 【问题描述】:

我有一个 SKView 和一个 MTKView 在一个应用程序中运行,到目前为止一切正常。

唯一的问题是,这两个视图在视觉上的整合很差。他们只是肩并肩。但我想让 SKView 内部的纯金属渲染与内部的一些 SKNode 一起移动。是SKView内部的一种快速显示。

在金属方面运行大量的计算和渲染工作。 SKView 应该为繁重的计算和纯金属部分的最小但非常快速的渲染提供一个很好的用户界面。

我已经考虑过使用带有 SpriteKit 场景叠加层的 SceneKit,因为 SCNRenderer 提供了使用 renderAtTime 渲染自己的 MTLCommandBuffer 和 MTLRenderPassDescriptor 的可能性。

我实现了下面的 SCNSceneRendererDelegate 方法并调用了我自己的渲染函数,它正在准备 commandBuffer。

func renderer(renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: NSTimeInterval) 
    nodeArray.render()

commandBuffer 准备好后,我调用 SCNRenderer 的 renderAtTime 方法。反复试验向我表明,在调用 renderAtTime 后必须提交命令缓冲区。如果我在应用程序崩溃之前这样做。如果我根本不这样做,它会冻结应用程序。

func bufferFinished(renderer:SCNRenderer, commandBuffer: MTLCommandBuffer, renderPassDescriptor: MTLRenderPassDescriptor)
    let current=CFAbsoluteTimeGetCurrent()
    renderer.renderAtTime(current, viewport: gameView.bounds, commandBuffer: commandBuffer, passDescriptor: renderPassDescriptor)
    commandBuffer.commit()

如果我这样做,应用程序正在运行,但没有显示额外的金属上下文。 我认为由于金属部分,整个事情有点复杂。

是否有任何简单的示例,其中纯金属在 SceneKit 视图中渲染或在 SpriteKit 视图中更好?

【问题讨论】:

SceneKit 和 SpriteKit 在“幕后”使用金属渲染您的内容。如果你想使用纯金属,那么你不能同时使用 SpriteKit 和 Metal。它们是两种不同的技术,目的不同。 不。与 UIKit 一样,Sprite Kit 和 Scene Kit 的用途都是 Metal 用途的部分子集。 Sprite Kit 和 Scene Kit 作为基于 Metal 的库会更有意义,但目前它们更像游戏引擎,除非它们是跨平台的,否则没有意义。 有办法做到这一点。例如使用 SCNRender:developer.apple.com/library/prerelease/ios/documentation/… 或使用 SCNSceneRenderer:developer.apple.com/library/prerelease/ios/documentation/… 【参考方案1】:

金属、SpriteKit 和 SceneKit

SpriteKit 和 SceneKit 一起工作。您可以在 SpriteKit 中使用 SceneKit,反之亦然。

在 SpriteKit 中,您可以使用 SK3DNode 来渲染 SceneKit 场景。这是一个示例:https://github.com/CloakedEddy/SK3DNode-example/tree/master/SKSCN%20Crossover

在 SceneKit 中,您可以使用 SCNView 继承的 SCNSceneRenderer 的 overlaySKScene 属性。您可以将 SpriteKit 场景与 SceneKit 场景并排渲染。

但是如何整合金属呢?

在 SpriteKit 中使用金属可以通过纹理来完成。您在 GPU 上使用金属计算纹理,并通过 modifyPixelDataWithBlock 将图像数据传输到 SKMutableTexture。这是可行的,但是您必须复制不好的数据,并且 SpriteKit 在幕后使用 OpenGL 而不是金属。所以它必须创建一个 OpenGL-Texture,正如你所见,这是非常昂贵的。

另一个问题是,如果您使用大型纹理以在 CPU 内存中获取它们,则必须同步 GPU 数据。只有这样您才能将数据复制到 SKMutableTexture。这是非常低效的,因为数据将再次进入 GPU,但现在使用 OpenGL。

使用 SceneKit,您可以选择是否要将 OpenGL 或 Metal 作为 GPU 的底层框架。并且可以直接用金属修改材质属性中的纹理。只需设置 SCNMaterialProperty 的内容属性。或者如果你想改变一个物体的几何形状,你可以直接通过金属修改SCNGeometrySource。

【讨论】:

根据这个文档 SpriteKit 默认使用 Metal:developer.apple.com/library/content/qa/qa1904/_index.html

以上是关于将纯 Metal-API 与 SceneKit 或 SpriteKit 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 SceneKit 的 Collada 文件中存储动画数据或任意数据?

SceneKit - 获取相机的方向

SpriteKit/Scenekit TouchesBegan 或 GestureRecognizer

如何在 SceneKit 中使用 OBJ 文件或 CTM 文件而不是 DAE 文件?

将纯文本文件中的 MySQL 转储导出为 JSON

SceneKit:围绕任意点进行轨道运行而无需相机跳跃或将锚点移动到中心?