MTKView纹理正确的颜色累积

时间:2018-12-15 01:56:09

标签: swift4 metal render-to-texture metalkit mtlbuffer

我正在研究一种金属支持的绘图应用程序,该应用程序通过沿路径重复冲压纹理正方形在MTKView上绘制笔触。我遇到了色彩累积问题,如下图所示:

snapshot of stamping implementation

对于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)

总而言之,我的问题是,如何以一种方式设置纹理/混合模式,对于任何图章透明度值,区域中绘制的累积结果最终将导致全彩色不透明度?任何指针将不胜感激。

0 个答案:

没有答案