Существует ли стандартный способ уменьшения размера текстурных изображений модели 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))")
}
}
}
}
}
}
}
}
}
}
}
}