22

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;
        }
    }
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Bob5421
  • 7,757
  • 14
  • 81
  • 175
  • Q1: Which macOS version are you using? snapshot is available only in 10.10+ Q2: What Mac hardware are you running this on? Metal is supported in Macs 2012 or later. See https://support.apple.com/en-us/HT205073. Also, on macOS, snapshot returns NSImage not UIImage. – sambro Feb 01 '17 at 21:33
  • The mac os x deployment target is v 10.11. My mac is Mid 2013. You are true about NSImage/UIImage – Bob5421 Feb 02 '17 at 07:08
  • Can you show some sample code? – sambro Feb 02 '17 at 21:00
  • Can't reproduce this behavior. With your source, snapshot() works with OpenGL and Metal APIs. macOS 10.11.6 iMac (27-inch, Late 2012), Xcode 8.1. – Ef Dot Feb 10 '17 at 08:56

1 Answers1

2

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

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220