CATextLayer 无法在 SCNNode 上正确渲染

Posted

技术标签:

【中文标题】CATextLayer 无法在 SCNNode 上正确渲染【英文标题】:CATextLayer not rendering properly on SCNNode 【发布时间】:2019-04-23 12:59:24 【问题描述】:

我有一个 CALayers 层次结构,我将其设置为我的 SCNNode 材质的漫反射属性。我使用以下代码对场景的当前状态(只有一个节点)进行快照,以将其另存为 PNG 文件:

scene.rootNode.addChildNode(node)
node.geometry?.firstMaterial?.diffuse.contents = self.createLayer() // CALayer

// Set transform of node.

let renderTime = CACurrentMediaTime() + 1
let size = CGSize(width: 600, height: 600)

let renderer = SCNRenderer(
  device: MTLCreateSystemDefaultDevice(),
  options: nil) 
let image = self.renderer.snapshot(
  atTime: renderTime,
  with: size,
  antialiasingMode: .multisampling4X)

return image

这通常有效,按预期渲染节点,但大约 25-50% 的时间,我拥有的任何 CATextLayer 作为self.createLayer() 中返回的层的子层都不会渲染文本。所有其他层似乎每次都渲染得很好。

例如,应该看起来像这样的图像:

最终缺少文本“N”:

图层本身正在渲染,我可以通过更改文本图层的背景颜色来确认:

这似乎只是在创建图层后立即出现的问题。如果我异步调度渲染代码,即使没有添加任何延迟,一切都会按预期呈现:

scene.rootNode.addChildNode(node)
node.geometry?.firstMaterial?.diffuse.contents = self.createLayer() // CALayer
// Set transform of node.
let renderTime = CACurrentMediaTime() + 1

let size = CGSize(width: 600, height: 600)
DispatchQueue.main.async 
  let image = self.renderer.snapshot(
    atTime: renderTime,
    with: size,
    antialiasingMode: .multisampling4X)

  completion(image)

上述解决方法似乎很老套,我不相信它是可靠的。另外,我不希望我的调用点以异步方式调用该方法。

SceneKit 或 CoreAnimation 中是否有我遗漏的属性或方法可以用来确保在尝试将其渲染到图像之前完全渲染图层?

【问题讨论】:

【参考方案1】:

我可以理解使用 DispatchMain 是不可靠的,因为您不确定节点是否已很好地呈现。所以有一个函数告诉你渲染是否完成。在该完成句柄内调用快照。

 scene.rootNode.addChildNode(node)
    node.geometry?.firstMaterial?.diffuse.contents = self.createLayer() // CALayer

    let renderer = SCNRenderer(
        device: MTLCreateSystemDefaultDevice(),
        options: nil)

----renderer.prepare([node])  (success) in  // this line is useful
        if (success)
            let renderTime = CACurrentMediaTime() + 1
            let size = CGSize(width: 600, height: 600)
            let  image = renderer.snapshot(
                atTime: renderTime,
                with: size,
                antialiasingMode: .multisampling4X)
            complete(image)
        
    

如果您认为加载时间过长,可以将其他节点添加到数组中。

【讨论】:

太棒了!这个调用不像我希望的那样同步,但这几乎正是我想要的!如果有同步版本,那就更好了,但这感觉比仅仅调度并希望一切正常。【参考方案2】:

通过在调用 sceneView.snapshot() 之前调用 SCNTransaction.flush(),我已经成功地制作了 PNG 快照。

【讨论】:

我尝试在创建快照之前添加SCNTransaction.flush(),但它仍然存在文本层不呈现文本的原始问题。

以上是关于CATextLayer 无法在 SCNNode 上正确渲染的主要内容,如果未能解决你的问题,请参考以下文章

解决CATextLayer在越狱设备上字体颜色问题。

CATextLayer 的动画foregroundColor 属性

SceneKit - 在另一个 SCNNode 上添加 SCNNode

CATextLayer 的动画截断

SceneKit:理解 SCNNode 的 pivot 属性

ARKIT:在一个SCNNode与另一个SCNNode之间画线时观察滞后