CATextLayer неправильно рендерится на SCNNode - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть иерархия CALayers, которую я устанавливаю в качестве свойства diffuse материала моего 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(), не отображает текст.Все остальные слои, кажется, каждый раз воспроизводятся очень хорошо.

Например, изображение, которое должно выглядеть так:

correct

В конце пропускается текст "N": incorrect

Сам слой визуализируется, что я могу подтвердить, изменив цвет фона текстового слоя:

enter image description here

Эта проблема возникает только после создания слоев.Если я отправляю код рендеринга асинхронно, даже без добавления какой-либо задержки, все рендеринг выполняется так, как ожидалось:

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, которые мне не хватает, которые я могу использовать, чтобы убедиться, что слойполностью отрисован перед попыткой рендерить его на изображение?

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

Мне удалось сделать снимки PNG, просто вызвав SCNTransaction.flush () перед вызовом sceneView.snapshot ().

0 голосов
/ 21 ноября 2018

Я могу понять, что использование 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)
        }
    }

Вы можете добавить другие узлы в массив, если считаете, что загрузка занимает слишком много времени.

...