在SceneKit中更新SCNMaterial纹理

iOS12ARKit 2的最新发行版中,Fueled决定开发一款名为Toppler的多设备AR游戏,以探索其某些功能。 在构建这种AR体验时,我们需要向用户提供有关将要选择和抓取哪个块的反馈。 我们最终决定对材料纹理进行运行时更新是必须的。 但是,这样做时,我们遇到了在构建SceneKit游戏时其他人也可能遇到的问题。

交换纹理

我们有两个要用作纹理的不同图像,具体取决于块状态:

我将跳过UV贴图,该贴图负责在块上展开纹理,但是如果您想在此处获得更多详细信息,我之前已经写过有关如何将3D模型从Blender导出到SceneKit的信息。

我决定通过根据材料状态提供条件源来处理此问题。 以下是该TopplerBlockMaterial类的简化版本,该类是SCNMaterial子类,负责处理块的可视状态:

事实证明,底层流程花费了将近22%的允许时间来渲染框架和创建图像材料。 CoreGraphics需要在将UIImage应用于材质之前在新的缓冲区中重绘UIImage ,这被证明是非常耗时的。

我们绝对必须寻找其他地方来更新纹理,而又不影响游戏和AR体验,而这需要恒定的帧频。

偏移纹理

花了几个小时在文档中寻找解决方案之后,我终于在SCNMaterialProperty上发现了一个有趣的实例属性  contentsTransform

事实证明,这正是我们所需要的。 这将允许我们创建一个包含两个不同状态的图像文件,然后我们可以偏移contentsTransform以仅显示纹理的所需部分。

这是新的纹理图像,红色矩形说明了可以用作contentsTransform的变换:

因此,我们需要使用两种不同的转换组合,一种用于普通,另一种用于突出显示状态。 这是使用此方法的更新后的TopplerBlockMaterial类:

我们遇到的这种阻止程序是一长串列表的一部分,当从UIKit发出来时,通常不会有人碰到 。 交换UIImageViewUIImage是一个非常简单的过程,不应引入性能问题。 但是在使用3D环境和SceneKit时 ,我们会遇到一些使用UIKit时通常不会遇到的意外的性能考虑。 希望本文也能对其他人有所帮助。