iosios-simulatortexturesmetalimage-formats

How do you specify a Metal texture format that's compatible with the iOS Simulator from an on-disk file?


Working with another post here as a starting point, I'm trying to do something similar. Pulling the .jpg texture from that post, my code runs just fine on a real device, but but fails in the simulator. The reason appears to be because of the image format.

As mentioned in Apple's documentation here, you can't use format MTLPixelFormat.r8Unorm_srgb which is I believe what that texture is encoded in, based on the following error:

failed assertion `pixelFormat (11) is not a valid MTLPixelFormat.'

Trying to figure out how to change the format, but no idea how to go about it. I don't know if it can be loaded into a particular color space at creation time, or if I have to do something specific in Photoshop, possibly even changing the file type altogether, but even there, I can't see how to turn off color profiles, just change them to something else.

So does anyone have any information on how one can create/load a texture that's also compatible with the simulator?

Update

Per someone asking, here's how I am setting the texture.

let noiseImage = UIImage(resourceName: "Noise", extension: "jpg")!
myMaterial.setValue(SCNMaterialProperty(contents: noiseImage), forKey: "noiseTexture")

Here's the convenience initializer the above uses...

extension UIImage {

    convenience init?(resourceName:String, extension:String? = nil, bundle:Bundle? = nil) {

        let bundle = bundle ?? Bundle.main

        guard let resourceFileName = bundle.path(forResource: resourceName, ofType: `extension`) else {
            return nil
        }

        self.init(contentsOfFile: resourceFileName)
    }
}

Solution

  • This appears to be a bug in SceneKit, which isn't accounting for the fact that certain pixel formats aren't supported on the iOS Simulator. You can work around it by manually creating a Metal texture with MetalKit instead:

    let textureLoader = MTKTextureLoader(device: scnView.device!)
    
    let noiseImage = UIImage(resourceName: "Noise", extension: "jpg")?.cgImage
    let texture = try! textureLoader.newTexture(cgImage: noiseImage!, options: [:])
    myMaterial.setValue(SCNMaterialProperty(contents: texture), forKey: "noiseTexture")