Как конвертировать металлическую текстуру в PNG и обратно ⇐ IOS
-
Гость
Как конвертировать металлическую текстуру в PNG и обратно
Я пытаюсь преобразовать текстуру металла в данные png (или любой другой формат, сжатый без потерь), чтобы сохранить их на диск.
После преобразования данных обратно в текстуру я хочу получить ту же текстуру без изменений.
У меня это работает с непрозрачными текстурами, но с прозрачными пикселями что-то идет не так.
Это код, который я использую для сжатия и распаковки текстуры.
public struct TextureCompresser { пусть контекст:CIContext пусть загрузчик: MTKTextureLoader общественный инициализации (устройство: MTLDevice) { загрузчик = MTKTextureLoader (устройство: устройство) контекст = CIContext(опции: [ CIContextOption.outputPremultiplied: ложь, ]) } общественная функция сжатия (текстура: MTLTexture) -> Данные? { let options:[CIImageOption:Any] = [CIImageOption.colorSpace:CGColorSpace(имя: CGColorSpace.linearSRGB)!] Guard let ciImage = CIImage(mtlTexture: текстура, параметры: параметры) еще {возвратить ноль} return context.pngRepresentation(of: ciImage, формат: .BGRA8, colorSpace: CGColorSpace(имя: CGColorSpace.sRGB)!)!) } public func decompress(png:Data) throws -> MTLTexture { let using = MTLTextureUsage(rawValue: MTLTextureUsage.renderTarget.rawValue | MTLTextureUsage.shaderRead.rawValue | MTLTextureUsage.shaderWrite.rawValue) пусть параметры: [MTKTextureLoader.Option: Любой] = [ MTKTextureLoader.Option.textureUsage:usage.rawValue, MTKTextureLoader.Option.origin:MTKTextureLoader.Origin.flippedVertically.rawValue, MTKTextureLoader.Option.SRGB:NSNumber(значение: true), MTKTextureLoader.Option.generateMipmaps:NSNumber(значение: false), ] вернуть попытку loader.newTexture(данные: png, параметры: параметры) } } Я поместил этот код в репозиторий здесь.
Обратите внимание, что я использую линейное цветовое пространство для параметров CIImage. Мне это кажется неправильным, поскольку мои текстуры имеют формат sRGB, но это был единственный способ заставить его работать вообще (но только для непрозрачных пикселей). Мои текстуры — bgra8Unorm_srgb.
Хотя это работает с непрозрачными пикселями, прозрачные пиксели изменяются. Например, тестовый пиксель преобразуется после сжатия/распаковки следующим образом:
[24, 72, 233, 78] -> [48, 127, 255, 78] Я перепробовал все возможные комбинации опций и цветовых пространств, которые только мог придумать, но ничего не помогло. Кто-нибудь знает, что я делаю не так?
Обновление – магия изображений
Я также просмотрел пиксели в полученном png-файле с помощью утилиты ImageMagik. Для тестового пикселя (24, 72, 233, 78) я получаю следующее:
0,0: (255,127,48,78) #FF7F304E srgba(255,127,48,0.305882) Это соответствует тому, что я получаю при загрузке текстуры (за исключением порядка, поскольку текстура BRG), поэтому похоже, что проблема связана с сохранением, а не с загрузкой.
Обновление: другие вопросы
Я просмотрел все похожие вопросы о переполнении стека, но ни один из них не касается этой проблемы. Ближайшие из них — эти два:
Сохранение и загрузка MTLTexture в формате PNG. Этот файл пытается сделать то же самое, но проблема в масштабе. Это не решает проблему, которую я описал.
Swift Metal сохраняет текстуру bgra8Unorm в файл PNG. Этот файл также пытается сохранить текстуру в формате PNG, но не упоминает о моей проблеме. Для создания PNG он использует немного другой API, но я проверил и обнаружил ту же проблему.
Я пытаюсь преобразовать текстуру металла в данные png (или любой другой формат, сжатый без потерь), чтобы сохранить их на диск.
После преобразования данных обратно в текстуру я хочу получить ту же текстуру без изменений.
У меня это работает с непрозрачными текстурами, но с прозрачными пикселями что-то идет не так.
Это код, который я использую для сжатия и распаковки текстуры.
public struct TextureCompresser { пусть контекст:CIContext пусть загрузчик: MTKTextureLoader общественный инициализации (устройство: MTLDevice) { загрузчик = MTKTextureLoader (устройство: устройство) контекст = CIContext(опции: [ CIContextOption.outputPremultiplied: ложь, ]) } общественная функция сжатия (текстура: MTLTexture) -> Данные? { let options:[CIImageOption:Any] = [CIImageOption.colorSpace:CGColorSpace(имя: CGColorSpace.linearSRGB)!] Guard let ciImage = CIImage(mtlTexture: текстура, параметры: параметры) еще {возвратить ноль} return context.pngRepresentation(of: ciImage, формат: .BGRA8, colorSpace: CGColorSpace(имя: CGColorSpace.sRGB)!)!) } public func decompress(png:Data) throws -> MTLTexture { let using = MTLTextureUsage(rawValue: MTLTextureUsage.renderTarget.rawValue | MTLTextureUsage.shaderRead.rawValue | MTLTextureUsage.shaderWrite.rawValue) пусть параметры: [MTKTextureLoader.Option: Любой] = [ MTKTextureLoader.Option.textureUsage:usage.rawValue, MTKTextureLoader.Option.origin:MTKTextureLoader.Origin.flippedVertically.rawValue, MTKTextureLoader.Option.SRGB:NSNumber(значение: true), MTKTextureLoader.Option.generateMipmaps:NSNumber(значение: false), ] вернуть попытку loader.newTexture(данные: png, параметры: параметры) } } Я поместил этот код в репозиторий здесь.
Обратите внимание, что я использую линейное цветовое пространство для параметров CIImage. Мне это кажется неправильным, поскольку мои текстуры имеют формат sRGB, но это был единственный способ заставить его работать вообще (но только для непрозрачных пикселей). Мои текстуры — bgra8Unorm_srgb.
Хотя это работает с непрозрачными пикселями, прозрачные пиксели изменяются. Например, тестовый пиксель преобразуется после сжатия/распаковки следующим образом:
[24, 72, 233, 78] -> [48, 127, 255, 78] Я перепробовал все возможные комбинации опций и цветовых пространств, которые только мог придумать, но ничего не помогло. Кто-нибудь знает, что я делаю не так?
Обновление – магия изображений
Я также просмотрел пиксели в полученном png-файле с помощью утилиты ImageMagik. Для тестового пикселя (24, 72, 233, 78) я получаю следующее:
0,0: (255,127,48,78) #FF7F304E srgba(255,127,48,0.305882) Это соответствует тому, что я получаю при загрузке текстуры (за исключением порядка, поскольку текстура BRG), поэтому похоже, что проблема связана с сохранением, а не с загрузкой.
Обновление: другие вопросы
Я просмотрел все похожие вопросы о переполнении стека, но ни один из них не касается этой проблемы. Ближайшие из них — эти два:
Сохранение и загрузка MTLTexture в формате PNG. Этот файл пытается сделать то же самое, но проблема в масштабе. Это не решает проблему, которую я описал.
Swift Metal сохраняет текстуру bgra8Unorm в файл PNG. Этот файл также пытается сохранить текстуру в формате PNG, но не упоминает о моей проблеме. Для создания PNG он использует немного другой API, но я проверил и обнаружил ту же проблему.
Мобильная версия