快速创建透明纹理

时间:2018-09-04 05:38:26

标签: swift compression metal metalkit uiimagepngrepresentation

我只需要创建一个透明的纹理。(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应该指向未压缩的数据。我该如何解决?

我是走正确的道路还是完全走错了方向?还有其他选择吗?我只需要创建透明的纹理即可。

1 个答案:

答案 0 :(得分: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.width),
                                     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 Land时避免开销和延迟的最好方法是尽快将图像放入GPU兼容的表示中。
  • 一旦您不在UIImage领域,请始终知道您的频道顺序(RGBA,BGRA)。在您正在编辑的代码中的任何时候,您都应该有一个心智模型来了解每个CVPixelBuffer / MTLTexture具有什么像素格式。
  • 阅读预乘和非预乘的alpha,您可能不会遇到问题,但是当我初次学习时,它使我反复离开。
  • 位图/像素缓冲区的总字节大小= bytesPerRow *高度