是否存在减小SceneKit模型纹理图像大小的标准方法?
WWDC 2018 talk about USDZ files说:“ 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))")
}
}
}
}
}
}
}
}
}
}
}
}