从头开始创建纯色纹理

Create solid color texture from a scratch

我正在创建一个引擎,需要为没有所需材料之一的对象创建虚拟单像素纹理。它应该是 4 通道纹理,示例调用如下所示:

let dummy = device.makeSolidTexture(device: device, color: simd_float4(0, 0, 1, 1))!
 

我正在使用的代码

extension MTLDevice {
    func makeSolidTexture(device: MTLDevice,
                          color: simd_float4,
                          pixelFormat: MTLPixelFormat = .bgra8Unorm) -> MTLTexture? {
        let descriptor = MTLTextureDescriptor()
        descriptor.width = 1
        descriptor.height = 1
        descriptor.mipmapLevelCount = 1
        descriptor.storageMode = .managed
        descriptor.arrayLength = 1
        descriptor.sampleCount = 1
        descriptor.cpuCacheMode = .writeCombined
        descriptor.allowGPUOptimizedContents = false
        descriptor.pixelFormat = pixelFormat
        descriptor.textureType = .type2D
        descriptor.usage = .shaderRead
        guard let texture = device.makeTexture(descriptor: descriptor) else {
            return nil
        }
        let origin = MTLOrigin(x: 0, y: 0, z: 0)
        let size = MTLSize(width: texture.width, height: texture.height, depth: texture.depth)
        let region = MTLRegion(origin: origin, size: size)
        withUnsafePointer(to: color) { ptr in
            texture.replace(region: region, mipmapLevel: 0, withBytes: ptr, bytesPerRow:  4)
        }
        return texture
    }
}

问题是当我在捕获帧后检查纹理时,我看到:

我想念什么?为什么是黑色的?

原来我在那里犯了两个错误。首先是纹理必须对齐到 256 字节,所以考虑到像素格式满足要求,我将大小扩展到 8 x 8。我的第二个错误是直接从浮点矢量创建纹理。纹理的底层类型存储数字在 0-255 范围内,因此传递给函数的 float 向量必须缩放然后转换为 simd_uchar4 类型。

它应该是这样的

extension MTLDevice {
    func makeSolid2DTexture(device: MTLDevice,
                            color: simd_float4,
                            pixelFormat: MTLPixelFormat = .bgra8Unorm) -> MTLTexture? {
        let descriptor = MTLTextureDescriptor()
        descriptor.width = 8
        descriptor.height = 8
        descriptor.mipmapLevelCount = 1
        descriptor.storageMode = .managed
        descriptor.arrayLength = 1
        descriptor.sampleCount = 1
        descriptor.cpuCacheMode = .writeCombined
        descriptor.allowGPUOptimizedContents = false
        descriptor.pixelFormat = pixelFormat
        descriptor.textureType = .type2D
        descriptor.usage = .shaderRead
        guard let texture = device.makeTexture(descriptor: descriptor) else {
            return nil
        }
        let origin = MTLOrigin(x: 0, y: 0, z: 0)
        let size = MTLSize(width: texture.width, height: texture.height, depth: texture.depth)
        let region = MTLRegion(origin: origin, size: size)
        let mappedColor = simd_uchar4(color * 255)
        Array<simd_uchar4>(repeating: mappedColor, count: 64).withUnsafeBytes { ptr in
            texture.replace(region: region, mipmapLevel: 0, withBytes: ptr.baseAddress!, bytesPerRow: 32)
        }
        return texture
    }
}
// bgra format in range [0, 1]
let foo = device.makeSolid2DTexture(device: device, color: simd_float4(1, 0, 0, 1))!