Сглаживание CGContext работает не так, как ожидалось, при рисовании на прозрачном фоне - PullRequest
0 голосов
/ 29 мая 2020

Пример взят из https://medium.com/@s1ddok / comb-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
    }

Вот как смешивается металл настроено

1025 *

1 Ответ

0 голосов
/ 01 июня 2020

Прочитав https://metalbyexample.com/translucency-and-transparency/, я заметил комментарий Уоррена Мура:

Поскольку вы загружаете свои текстуры с помощью CoreGraphics, вы получаете предварительно умноженную альфа-версию (т.е. цветовые каналы уже умножены на их соответствующие альфа-значения). Следствием использования предварительно умноженного альфа с коэффициентами смешения SourceAlpha, OneMinusSourceAlpha является избыточное умножение исходного альфа-значения, в результате чего области с <1.0 становятся неестественно темными. Если вместо этого вы используете коэффициенты смешивания One, OneMinusSourceAlpha, вы получите гораздо более приятный результат. Кстати, это основная причина, по которой я использовал непрозрачную текстуру и полупрозрачные цвета вершин при демонстрации смешивания в статье. </p>

Помогло изменение sourceAlpha на One. К сожалению, предварительное умножение альфа в CGContext не может быть отключено

...