[CGContext抗锯齿在透明背景上绘制时无法正常工作

问题描述 投票:0回答:1

示例取自https://medium.com/@s1ddok/combine-the-power-of-coregraphics-and-metal-by-sharing-resource-memory-eabb4c1be615。刚刚将颜色空间从r8unorm更改为rgba8unorm。

// CGContext created with aligned data, which shared with MTLTexture
let cgContext = textureContext.cgContext
        let clearRect = CGRect(
                origin: .zero,
                size: CGSize(width: cgContext.width, height: cgContext.height)
        )
        cgContext.setAllowsAntialiasing(true)
        cgContext.setShouldAntialias(true)
        cgContext.clear(clearRect)

        cgContext.addPath(path)
        cgContext.setFillColor(fillColor ?? UIColor.clear.cgColor)
        cgContext.fillPath(using: fillRule.cgFillRuleValue())

共享数据块上的渲染路径然后用作在MTKView的纹理上渲染的四元图元的纹理。但是有一个问题-抗锯齿会在这样的边缘上混合路径填充颜色和清晰的(黑色)颜色(希望此图片之间的差异明显)-Dirty color on smooth edges

这是正常重叠,当我用红色预填充上下文区域时Correct overlap

如果在上下文中关闭了抗锯齿功能,则边缘会明显变白,但会变清晰

是否有办法在没有绘制平滑路径的情况下将两个纹理清晰且平滑的边缘重叠在一起,而不会在重叠的纹理上渲染适当的重叠纹理块?

UPD:如何创建上下文

func createCGMTLContext(withSize size: CGSize) -> CGMTLContext? {
        let width = Int(size.width)
        let height = Int(size.height)

        let pixelRowAlignment = device.minimumTextureBufferAlignment(for: .rgba8Unorm)
        let bytesPerRow = alignUp(size: width, align: pixelRowAlignment) * 4

        let pagesize = Int(getpagesize())
        let allocationSize = alignUp(size: bytesPerRow * height, align: pagesize)
        var data: UnsafeMutableRawPointer? = nil
        let result = posix_memalign(&data, pagesize, allocationSize)
        if result != noErr {
            fatalError("Error during memory allocation")
        }

        let context = CGContext(data: data,
                width: width,
                height: height,
                bitsPerComponent: 8,
                bytesPerRow: bytesPerRow,
                space: CGColorSpaceCreateDeviceRGB(),
                bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!

        context.scaleBy(x: 1.0, y: -1.0)
        context.translateBy(x: 0, y: -CGFloat(context.height))

        let buffer = device.makeBuffer(
                bytesNoCopy: context.data!,
                length: allocationSize,
                options: .storageModeShared,
                deallocator: { pointer, length in free(data) }
        )!

        let textureDescriptor = MTLTextureDescriptor()
        textureDescriptor.pixelFormat = .rgba8Unorm
        textureDescriptor.width = context.width
        textureDescriptor.height = context.height
        textureDescriptor.storageMode = buffer.storageMode
        textureDescriptor.usage = .shaderRead

        let texture = buffer.makeTexture(descriptor: textureDescriptor,
                offset: 0,
                bytesPerRow: context.bytesPerRow)

        guard let requiredTexture = texture else {
            return nil
        }

        let cgmtlContext = CGMTLContext(
                cgContext: context,
                buffer: buffer,
                texture: requiredTexture
        )

        return cgmtlContext
    }

如何设置金属混合

pipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
            pipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
            pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
            pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
            pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
            pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
core-graphics metal cgcontext antialiasing
1个回答
0
投票

[阅读https://metalbyexample.com/translucency-and-transparency/之后,我注意到沃伦·摩尔的评论:

由于您要在CoreGraphics中加载纹理,所以您会获得预乘Alpha(即颜色通道已经乘以它们各自的Alpha值)。将预乘alpha与SourceAlpha和OneMinusSourceAlpha混合因子一起使用的结果是,将源alpha值多余地相乘,从而导致<1.0的区域变得不自然地变暗。相反,如果使用One,OneMinusSourceAlpha混合因子,则会得到令人愉悦的结果。顺便说一句,这是我在文章中演示混合时使用不透明纹理和半透明顶点颜色的主要原因。

将sourceAlpha更改为One有所帮助。不幸的是,无法关闭CGContext中的Alpha预乘]

© www.soinside.com 2019 - 2024. All rights reserved.