0

我只需要创建一个透明纹理。(带有 alpha 0 的像素)。

func layerTexture()-> MTLTexture {

        let width = Int(self.drawableSize.width  )
        let height = Int(self.drawableSize.height )


        let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .bgra8Unorm, width: width , height: height, mipmapped: false)
        let temparyTexture = self.device?.makeTexture(descriptor: texDescriptor)

        return temparyTexture!
    }

当我使用预览打开 temparyTexture 时,它​​似乎是黑色的。这里缺少什么?

更新

我只是尝试使用透明图像创建纹理。代码。

 func layerTexture(imageData:Data)-> MTLTexture {

        let width = Int(self.drawableSize.width  )
        let height = Int(self.drawableSize.height )
        let bytesPerRow = width * 4


        let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: width , height: height, mipmapped: false)

        let temparyTexture = self.device?.makeTexture(descriptor: texDescriptor)

         let region = MTLRegionMake2D(0, 0, width, height)

        imageData.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
            let rawPtr = UnsafeRawPointer(u8Ptr)

            temparyTexture?.replace(region: region, mipmapLevel: 0, withBytes: rawPtr, bytesPerRow: bytesPerRow)
        }


        return temparyTexture!
    }

方法被调用如下

let image = UIImage(named: "layer1.png")!

let imageData = UIImagePNGRepresentation(image)

self.layerTexture(imageData: imageData!)

其中 layer1.png 是一个透明的 png。但即使它在我尝试替换纹理时出现消息“线程 1:EXC_BAD_ACCESS (code=1, address=0x107e8c000)”崩溃。我相信这是因为图像数据是压缩的,而 rawpointer 应该指向未压缩的数据。我该如何解决这个问题?

我是在正确的道路上还是完全在错误的方向上?有没有其他选择。我只需要创建透明纹理。

4

1 回答 1

2

预编辑:当您快速查看透明纹理时,它会显示为黑色。我只是仔细检查了一些我在生产中稳定运行的代码——这是预期的结果。

后期编辑:你是对的,你不应该直接将 PNG 或 JPEG 数据复制到 MTLTexture 的内容中。我建议做这样的事情:

    var pixelBuffer: CVPixelBuffer?

    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
                 kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue,
                 kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue]

    var status = CVPixelBufferCreate(nil, Int(image.size.width), Int(image.size.height),
                                     kCVPixelFormatType_32BGRA, attrs as CFDictionary,
                                     &pixelBuffer)
    assert(status == noErr)

    let coreImage = CIImage(image: image)!
    let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
    context.render(coreImage, to: pixelBuffer!)

    var textureWrapper: CVMetalTexture?

    status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                       GPUManager.shared.textureCache, pixelBuffer!, nil, .bgra8Unorm,
                                                       CVPixelBufferGetWidth(pixelBuffer!), CVPixelBufferGetHeight(pixelBuffer!), 0, &textureWrapper)

    let texture = CVMetalTextureGetTexture(textureWrapper!)!

    // use texture now for your Metal texture. the texture is now map-bound to the CVPixelBuffer's underlying memory.

您遇到的问题是,实际上很难完全掌握位图的工作原理以及它们如何以不同的方式布局。图形是一个非常封闭的领域,有很多深奥的术语,其中一些是指需要数年时间才能掌握的东西,其中一些是指微不足道但人们只是选择了一个奇怪的词来称呼它们的东西。我的主要指示是:

  • 尽可能早地在你的代码中离开 UIImage 领域。进入 Metal 领域时避免开销和延迟的最佳方法是尽快将图像转换为与 GPU 兼容的表示。
  • 一旦你在 UIImage 领域之外,总是知道你的频道顺序(RGBA,BGRA)。在您正在编辑的代码中的任何一点,您都应该对每个 CVPixelBuffer / MTLTexture 具有的像素格式有一个心智模型。
  • 阅读预乘与非预乘 alpha,你可能不会遇到这个问题,但是当我第一次学习时它反复让我失望。
  • 位图/像素缓冲区的总字节大小 = bytesPerRow * height
于 2018-09-07T20:28:41.980 回答