Blending images in Metal

时间:2018-02-01 18:25:13

标签: macos metal

I've been trying to learn Metal and have become stuck when trying to blend two images together.

I've got two, textured quads with the opacity of one set to 0.5 and it's scaled to 75% of the other's size.

The quads are:

enter image description here

and

enter image description here

The MTKView is cleared with red. When I try to blend them the result is:

enter image description here

what I'm expecting is:

enter image description here

For my pipeline setup I'm using:

descriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
descriptor.colorAttachments[0].isBlendingEnabled = true
descriptor.colorAttachments[0].rgbBlendOperation = .add
descriptor.colorAttachments[0].alphaBlendOperation = .add
descriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
descriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
descriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
descriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha

The Metal shader functions are:

vertex VertexOut vertex_shader(const VertexIn vertex_in [[ stage_in ]], constant ModelMatrix &matrix [[ buffer(1) ]], constant const UniformsStruct &uniforms [[ buffer(2) ]]) {
    VertexOut vertex_out;
    vertex_out.position = matrix.mvpMatrix * vertex_in.position;
    vertex_out.colour = vertex_in.colour;
    vertex_out.textureCoordinates = vertex_in.textureCoordinates;
    vertex_out.opacity = uniforms.opacity;
    return vertex_out;
}

fragment half4 masked_textured_fragment_shader(VertexOut vertex_from_vertex_shader [[ stage_in ]], sampler sampler2d [[ sampler(0) ]], texture2d<float> mask [[ texture(1) ]], texture2d<float> texture [[ texture(0) ]]) {
    float4 keyPixel = mask.sample(sampler2d, vertex_from_vertex_shader.textureCoordinates);
    float4 colour = texture.sample(sampler2d, vertex_from_vertex_shader.textureCoordinates);
    return half4(colour.r * keyPixel.r, colour.g * keyPixel.g, colour.b * keyPixel.b, vertex_from_vertex_shader.opacity);
}

My current best guess is the pipeline isn't set with the correct options but changing them doesn't make the two quads blend but does give some interesting effects!

1 个答案:

答案 0 :(得分:1)

为第二个四边形设置正确的管道状态是实现混合所必须做的唯一事情 - 您不必在片段函数中进行任何计算。

尝试设置一个简单的管道,没有后四边形的混合。 然后像上面的前四边形一样设置管道。

渲染两个四边形时,切换管道状态,使后四边形渲染而不混合,前四边形渲染与混合。

blending

得到上面的结果,这是两个四边形的片段函数:

fragment float4 fragment_main (VertexOut in [[ stage_in ]],
                   texture2d<float> texture [[ texture(0) ]]) {
  constexpr sampler sampler2d;
  float4 color = texture.sample(sampler2d, in.textureCoordinates);
  color.a = 0.5;  // set opacity. Ignored if blending is not enabled
  return color;
}

这是“固定功能”混合 - 您可以通过使用两种不同的管道状态来设置GPU的状态。

您可以在Metal By Example

了解更多相关信息