MTKView vertex transparency is not getting picked up in “additive” blending mode

蓝咒 提交于 2019-12-11 16:22:16

问题


I am trying to implement a metal-backed drawing application where brushstrokes are drawn on an MTKView by stamping a textured square repeatedly along a path. I am varying the stamp's color/transparency at the vertex level as the brushstroke is drawn so I can simulate ink effects such as color/transparency fading over time, etc. This seems to work ok when I am using a classic "over" type blending (which does not accumulate value over time), but when I use "additive" blending, vertex transparency is completely ignored (i.e. I only get texture transparency). Below are snippets of pertinent code:

First, my vertex program:

vertex VertexOut basic_vertex(const device VertexIn* vertex_array [[ buffer(0) ]], unsigned int vid [[ vertex_id ]]) {

  VertexIn VertexIn = vertex_array[vid];   
  VertexOut VertexOut;
  VertexOut.position = float4(VertexIn.position,1);
  VertexOut.color = VertexIn.color;             
  VertexOut.texCoord = VertexIn.texCoord;

  return VertexOut;
}

Next, my fragment program multiplies the stamp's texture (with alpha) by the vertex color (also with alpha) which is needed for gradual tinting or fading of each stamp across a brushstroke

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;
}

Next, below are the blending definitions:

// 5a. Define render pipeline settings
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexFunction = vertexProgram
renderPipelineDescriptor.sampleCount = self.sampleCount
renderPipelineDescriptor.colorAttachments[0].pixelFormat = self.colorPixelFormat
renderPipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
renderPipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add

// settings for additive blending
if drawColorBlendMode == colorBlendMode.compositeAdd {
  renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .one
  renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .one
  renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
  renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .one
}

// settings for classic 'over' blending
if drawColorBlendMode == colorBlendMode.compositeOver {
   renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
   renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
   renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
   renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
}

renderPipelineDescriptor.fragmentFunction = fragmentProgram

Finally, my render encoding:

brushTexture = MetalTexture(resourceName: "stamp_stipple1_0256", ext: "png", mipmaped: true)
brushTexture.loadTexture(device: device!, commandQ: commandQueue, flip: true)
renderCommandEncoder?.setRenderPipelineState(renderPipeline!)
renderCommandEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderCommandEncoder?.setFragmentTexture(brushTexture.texture, index: 0)
renderCommandEncoder?.setFragmentSamplerState(samplerState, index: 0)

Is there anything I'm missing? As stated earlier, this works as expected in "over" mode, but not in "additive" mode. Again, the desired effect is that to pass varying color/transparency settings to each stamp (pair of textured triangles).


回答1:


Through trial and error, I arrived at the following settings to get what I was after:

// Settings for compositeOver
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .one
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha

Also, because I was dealing with many overlapping stamps, I had to divide the color/alpha values by the number of overlaps in order to avoid over-saturation. I think this, more than anything was the reason i was not seeing color/alpha accumulation the way i expected.

stampColor = UIColor(red: (rgba.red * rgba.alpha / numOverlappingStamps), green: (rgba.green * rgba.alpha / numOverlappingStamps), blue: (rgba.blue * rgba.alpha / numOverlappingStamps), alpha: (rgba.alpha / numOverlappingStamps))


来源:https://stackoverflow.com/questions/48713020/mtkview-vertex-transparency-is-not-getting-picked-up-in-additive-blending-mode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!