'SceneKit Cocoa snapshot failed assertion

I am working on a Swift/Cocoa/Xcode application.

This application contains a SceneKit View. The rendering API is set to Default (I think this is Metal).

If I run a snapshot() on this SceneKit view object, I get this error message. What I want to do is to capture an UIImage of the scene, viewed from camera

Texture PixelFormat MTLPixelFormatBGRA8Unorm does not match Resolve PixelFormat MTLPixelFormatRGBA8Unorm

If I set the rendering API to OpenGL, I have no error, everything works.

I have tried the same thing on an iOS app, it works on both cases (Metal or OpenGL).

I do not understand why I get this error and what should I do to avoid it.

Here is sample code:

    import SceneKit
    import Cocoa

    class ViewController: NSViewController {

        @IBOutlet weak var vue_scene: SCNView!
        @IBOutlet weak var img_snapshot: NSImageView!

        let camera_node = SCNNode()
        var box_node:SCNNode = SCNNode()

        override func viewDidLoad() {
            super.viewDidLoad()

            let scene = SCNScene()
            vue_scene.scene = scene

            vue_scene.backgroundColor = NSColor.clear

            vue_scene.showsStatistics = false
            vue_scene.allowsCameraControl = false
            vue_scene.autoenablesDefaultLighting = true

            camera_node.camera = SCNCamera()
            camera_node.camera?.zNear = 0.01
            camera_node.camera?.zFar = 1000000.0
            vue_scene.pointOfView = camera_node
            vue_scene.scene!.rootNode.addChildNode(camera_node)

            let box = SCNBox(width: 10.0, 
                            height: 10.0, 
                            length: 10.0, 
                     chamferRadius: 0.0)
            box.firstMaterial?.diffuse.contents = NSColor.red

            box.firstMaterial?.isDoubleSided = true
            box_node = SCNNode(geometry:box)
            box_node.position = SCNVector3Make(0,0,0)
            box_node.opacity = 1.0
            vue_scene.scene!.rootNode.addChildNode(box_node)

            camera_node.position = SCNVector3Make(0.0,
                                                  0.0,
                                                 70.0)
        }

        @IBAction func on_btn(_ sender: Any) {
            // signal SIGABRT here:
            // /Library/Caches/com.apple.xbs/Sources/Metal/Metal-56.6.1/ToolsLayers/Debug/MTLDebugCommandBuffer.mm:215: failed assertion `Texture PixelFormat MTLPixelFormatBGRA8Unorm does not match Resolve PixelFormat MTLPixelFormatRGBA8Unorm'
            let image = vue_scene.snapshot()
            img_snapshot.image = image;
        }
    }


Solution 1:[1]

It works on Metal.

In macOS use Tab View (for example) for accommodation of SceneView and NSImageView.

I also tested it in Xcode 13.3 on macOS 12.3 Monterey.

import SceneKit
import Cocoa

class ViewController: NSViewController {
    
    @IBOutlet var sceneView: SCNView!
    @IBOutlet var imageView: NSImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()            
        sceneView.scene = SCNScene()
        
        sceneView.pointOfView?.position.z = 20
        sceneView.allowsCameraControl = true
        sceneView.showsStatistics = true
        sceneView.backgroundColor = NSColor.black
        sceneView.autoenablesDefaultLighting = true

        let box = SCNBox(width: 1.0, height: 1.0,
                        length: 1.0, chamferRadius: 0.0)
        
        box.firstMaterial?.diffuse.contents = NSColor.systemTeal

        let boxNode = SCNNode(geometry: box)
        boxNode.position = SCNVector3(0,0,-10)
        sceneView.scene!.rootNode.addChildNode(boxNode)
    }
    
    @IBAction func createSnapshot(_ sender: NSButton) {
        let image = sceneView.snapshot()
        imageView.image = image
    }
}

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1