我正在开发一个金属支持的绘图应用程序,其中笔触是通过沿路径反复压印纹理正方形在 MTKView 上绘制的。我遇到了颜色累积问题,如下图所示:
对于 alpha 值 [0.5 - 1.0],结果或多或少符合我的预期。但是,对于较小的 alpha 值,结果看起来不完整,并且永远无法达到原始完全不透明画笔颜色的均匀/正确饱和值(即,如上图中的顶部笔触)。
我的方法的一个关键概念是以下(可能有缺陷的)实现:比如说,所需的画笔颜色是蓝色,如上:
brushColor = (r: 0.0, g: 0.0, b:1.0, a: 1.0)
我设置每个 stampColor 的方式是通过将 BrushColor 除以重叠图章的数量:
overlapStampCount = n
stampColor = (r: 0.0/overlapStampCount, g: 0.0/overlapStampCount, b:1.0/overlapStampCount, a:1.0/overlapStampCount)
.
这个想法是 n 个重叠的图章将累积加起来为画笔颜色(蓝色)。每个图章在每个顶点使用此 stampColor 将圆形斑点的白色纹理与 alpha 设置相乘。下面是我的片段着色器:
fragment float4 basic_fragment(VertexOut interpolated [[stage_in]], texture2d<float> tex2D [[ texture(0) ]],
sampler sampler2D [[ sampler(0) ]]) {
float4 color = interpolated.color * tex2D.sample(sampler2D, interpolated.texCoord); // texture multiplied by vertex color
return color;
}
.
因此,基于这个概念,我着手寻找一种混合模式,可以给我想要的结果。经过反复试验,我得出了以下混合设置,以达到上图的效果:
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .one
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
.
在一个相关的帖子中,有人建议我使用“Source Over Compositing”
cdst′ = αsrc * csrc + (1 - αsrc) * cdst
...翻译为:
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
.
但结果与预期的结果相去甚远。
我正在使用的纹理是从 png 文件(具有透明度)构建的,如下所示:
let image = UIImage(contentsOfFile: path)!.cgImage!
let colorSpace = CGColorSpaceCreateDeviceRGB()
width = image.width
height = image.height
let rowBytes = width * bytesPerPixel
let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: rowBytes, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let bounds = CGRect(x: 0, y: 0, width: Int(width), height: Int(height))
context.clear(bounds)
if flip == false {
context.translateBy(x: 0, y: CGFloat(self.height))
context.scaleBy(x: 1.0, y: -1.0)
}
context.draw(image, in: bounds)
let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.rgba8Unorm, width: Int(width), height: Int(height), mipmapped: isMipmaped)
texture = device.makeTexture(descriptor: texDescriptor)
.
总而言之,我的问题是,我如何设置我的纹理/混合模式,对于任何印章透明度值,在一个区域中绘制的累积结果最终会导致全色不透明度?任何指针将不胜感激。