问题
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