CATextLayer 无法在 SCNNode 上正确呈现
CATextLayer not rendering properly on SCNNode
我有一个 CALayer 层次结构,我将其设置为我的 SCNNode material 的扩散 属性。我拍摄了场景的当前状态(只有一个节点)的快照,以使用以下代码将其另存为 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% 的时间,我作为 self.createLayer()
中返回的层的子层的任何 CATextLayer 不渲染文本。所有其他层似乎每次都渲染得很好。
例如,应该看起来像这样的图像:
最终缺少文本 "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 中是否有我遗漏的 属性 或方法,我可以使用它来确保图层在尝试将其渲染为图像之前已完全渲染?
我可以理解使用 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)
}
}
如果您认为加载时间过长,您可以将其他节点添加到数组中。
我通过在调用 sceneView.snapshot() 之前调用 SCNTransaction.flush() 成功制作了 PNG 快照。
我有一个 CALayer 层次结构,我将其设置为我的 SCNNode material 的扩散 属性。我拍摄了场景的当前状态(只有一个节点)的快照,以使用以下代码将其另存为 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% 的时间,我作为 self.createLayer()
中返回的层的子层的任何 CATextLayer 不渲染文本。所有其他层似乎每次都渲染得很好。
例如,应该看起来像这样的图像:
最终缺少文本 "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 中是否有我遗漏的 属性 或方法,我可以使用它来确保图层在尝试将其渲染为图像之前已完全渲染?
我可以理解使用 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)
}
}
如果您认为加载时间过长,您可以将其他节点添加到数组中。
我通过在调用 sceneView.snapshot() 之前调用 SCNTransaction.flush() 成功制作了 PNG 快照。