首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将16位图像加载到金属纹理中?

如何将16位图像加载到金属纹理中?
EN

Stack Overflow用户
提问于 2018-02-19 18:21:38
回答 1查看 1.3K关注 0票数 2

推荐的使用MTKTextureLoader.newTexture的方法不适用于16位图像。

  1. named:版本静默地将图像转换为8位像素格式。
  2. cgImage:版本以Image decoding failed终止。

UIImage和NSImage都支持加载16位映像,并且有它们方便的.cgimage方法,这种方法可以在一个队列中转换为CGImage,从而解决了在这两个平台上获取CGImage的问题。

如何编写转换CGImage并返回16位金属纹理的函数?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-20 21:40:11

下面的loadEXRTexture函数加载一个扩展范围的图像,并将其像素转换为半精度浮点,将产生的像素数据存储为具有.rgba16Float格式的MTLTexture。它试图通过使用CGImageSource选项来保留浮点图像的原始范围,这些选项改变了Quartz默认值的行为(该选项应用了一个“解码”函数,该函数将源数据压缩到适合绘制位图上下文的范围中)。它假设由图像源创建的图像有三个浮点组件,按RGB顺序填充。

代码语言:javascript
运行
复制
func convertRGBF32ToRGBAF16(_ src: UnsafePointer<Float>, _ dst: UnsafeMutablePointer<UInt16>, pixelCount: Int) {
    for i in 0..<pixelCount {
        storeAsF16(src[i * 3 + 0], dst + (i * 4) + 0)
        storeAsF16(src[i * 3 + 1], dst + (i * 4) + 1)
        storeAsF16(src[i * 3 + 2], dst + (i * 4) + 2)
        storeAsF16(1.0, dst + (i * 4) + 3)
    }
}

func loadEXRTexture(_ url: URL, device: MTLDevice) -> MTLTexture? {
    guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil }

    let options = [ kCGImageSourceShouldCache : true, kCGImageSourceShouldAllowFloat : true ] as CFDictionary
    guard let image = CGImageSourceCreateImageAtIndex(imageSource, 0, options) else { return nil }

    let descriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba16Float,
                                                              width: image.width,
                                                              height: image.height,
                                                              mipmapped: false)
    descriptor.usage = .shaderRead
    guard let texture = device.makeTexture(descriptor: descriptor) else { return nil }

    if image.bitsPerComponent == 32 && image.bitsPerPixel == 96 {
        let srcData: CFData! = image.dataProvider?.data
        CFDataGetBytePtr(srcData).withMemoryRebound(to: Float.self, capacity: image.width * image.height * 3) { srcPixels in
            let dstPixels = UnsafeMutablePointer<UInt16>.allocate(capacity: 4 * image.width * image.height)
            convertRGBF32ToRGBAF16(srcPixels, dstPixels, pixelCount: image.width * image.height)
            texture.replace(region: MTLRegionMake2D(0, 0, image.width, image.height),
                            mipmapLevel: 0,
                            withBytes: dstPixels,
                            bytesPerRow: MemoryLayout<UInt16>.size * 4 * image.width)
            dstPixels.deallocate()
        }
    }

    return texture
}

您需要将此实用工具包含在桥接头中,因为据我所知,Swift没有__fp16类型或任何类似的类型:

代码语言:javascript
运行
复制
#include <stdint.h>
static inline void storeAsF16(float value, uint16_t *pointer) { *(__fp16 *)pointer = value; }
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48872043

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档