我正在研究一种金属支持的绘图应用程序,该应用程序通过沿路径重复冲压纹理正方形在MTKView上绘制笔触。我遇到了色彩累积问题,如下图所示:
对于alpha值[0.5-1.0],结果或多或少是我期望的。但是,对于较小的Alpha值,结果看起来不完整,并且永远无法达到原始完全不透明画笔颜色的统一/正确饱和度值(即,如上图中的顶部画笔笔触)。
我的方法的一个关键概念是以下(可能是有缺陷的)实现:比如,所需的brushColor为蓝色,如上所述:
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个重叠的图章将累加起来为brushColor(蓝色)。每个图章在每个顶点使用此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
。
在相关的post上,建议我使用“合成时的源代码”
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)
。
总而言之,我的问题是,如何以一种方式设置纹理/混合模式,对于任何图章透明度值,区域中绘制的累积结果最终将导致全彩色不透明度?任何指针将不胜感激。