Лучший способ уменьшить образы текстур модели SceneKit? - PullRequest
0 голосов
/ 01 января 2019

Существует ли стандартный способ уменьшения размера текстурных изображений модели SceneKit?

В WWDC 2018 о файлах USDZ говорится: «AR Quick Look будет динамически сокращать текстуры для других устройств при необходимости».Но мы используем SceneKit напрямую, а не через Quick Look, поэтому мне интересно, есть ли опция или методика в SceneKit или Model I / O для динамического сокращения текстурных изображений?

Я реализовал свой собственныйРасширение SCNode для использования после загрузки модельной сцены, но оно немного медленное, и я не совсем уверен, что оно оптимально:

extension SCNode {

    func downsampleTextures(maxSize: Int = 512) {

    let options = [kCGImageSourceThumbnailMaxPixelSize: maxSize, kCGImageSourceCreateThumbnailWithTransform: true, kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceCreateThumbnailFromImageIfAbsent: true] as CFDictionary

    // Resize material texture images in the model that are too big.
    self.enumerateHierarchy { (childNode, stop) in
        if let geometry = childNode.geometry {
            for material in geometry.materials {
                for materialProperty in [material.ambientOcclusion, material.diffuse, material.displacement, material.emission, material.metalness, material.multiply, material.roughness, material.normal, material.reflective, material.specular, material.transparent] {
                    autoreleasepool {

                        if let texture = materialProperty.contents as? MDLURLTexture, texture.dimensions.x > maxSize {

                            NSLog("Downsampling URL \(material.name ?? "material") in \(self.name ?? "") from \(texture.dimensions) to (\(maxSize), \(maxSize)), \(texture.url)")
                            if let imageSource = CGImageSourceCreateWithURL(texture.url as CFURL, [kCGImageSourceShouldCache: false] as CFDictionary) {

                                if let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options) {
                                    materialProperty.contents = cgImage
                                }
                            }
                        } else if let texture = materialProperty.contents as? MDLTexture {
                            if texture.dimensions.x > maxSize, let image = texture.imageFromTexture()?.takeUnretainedValue() {
                                NSLog("Downsampling image \(material.name ?? "material") in \(self.name ?? "") from \(texture.dimensions) to (\(maxSize), \(maxSize))")
                                materialProperty.contents = image.resized(toWidth: maxSize, toHeight: maxSize)
                            }
                        } else if let imageData = materialProperty.contents as? Data, let image = UIImage.init(data: imageData)?.cgImage {
                            if image.width > maxSize {
                                NSLog("Downsampling data \(self.name ?? "") from (\(image.width), \(image.height)) to (\(maxSize), \(maxSize))")
                                materialProperty.contents = image.resized(toWidth: maxSize, toHeight: maxSize)
                            }
                        } else if let texturePath = materialProperty.contents as? String {

                            if let url = Bundle.main.url(forResource: texturePath, withExtension: nil) {
                                if let imageSource = CGImageSourceCreateWithURL(url as CFURL, [kCGImageSourceShouldCache: false] as CFDictionary),
                                    let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [NSString: AnyObject] {
                                    if let width = properties[kCGImagePropertyPixelWidth] as? NSNumber, width.intValue > maxSize {
                                        if let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options) {
                                            materialProperty.contents = cgImage
                                            NSLog("Downsampling path \(url.lastPathComponent) in \(self.name ?? "") from \(width) to (\(cgImage.width), \(cgImage.height))")
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

}

...