5

For whatever reason I am having issues with alpha blending in metal. I am drawing to a MTKView and for every pipeline that I create I do the following:

descriptor.colorAttachments[0].blendingEnabled = YES;
descriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
descriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
descriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
descriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;

However for whatever reason that is not causing alpha testing to happen. You can even check in the frame debugger and you will see vertices with an alpha of 0 that are being drawn black rather than transparent.

One thought I had is that some geometry ends up on the exact same z plane so if alpha blending does not work on the same z plane that might cause an issue. But I dont think that is a thing.

Why is alpha blending not working?

I am hoping to blend as if they were transparent glass. Think like this.

enter image description here

J.Doe
  • 1,502
  • 13
  • 47
  • Are you expecting parts of the view to end up transparent so views/windows behind it are visible? Or is there some existing rendering in the same view that's being drawn over? What's the load action for the color attachment? If it's "clear", what is the clear color? – Ken Thomases Aug 27 '18 at 14:24
  • Clear color is the background color which is black. Each frame the load action is clear so everything is cleared to black. There are a lot of 2D triangles drawn each with various levels of transparency. So the hope is that their transparency is visible. – J.Doe Aug 27 '18 at 17:37
  • Given the blending you're using, if a triangle is drawn with transparency on black, you "see" the black through the triangle. It doesn't punch a transparent hole in the black. I ask again: do you want your view to end up partially transparent so views/windows behind it are visible? – Ken Thomases Aug 27 '18 at 17:40
  • Correct. The problem is that two triangles of half transparency drawn over each-other would result in a dark triangle of the color of whichever one has lesser depth. Essentially the one of lesser depth blocked the one of greater depth from contributing to the color. – J.Doe Aug 27 '18 at 17:42
  • I am essentially looking for the look of glass overlapping. I updated the question with a picture. – J.Doe Aug 27 '18 at 17:45
  • If you want to render the above, you need to clear to white and not black for a start. – Matthias Aug 27 '18 at 17:54
  • @Matthias I have updated the picture. I dont want additive blending. – J.Doe Aug 27 '18 at 18:13
  • @J.Doe I know since this question is not about additive but alpha blending. Your blend state is correct for alpha blending, but you must first render the opaque geometry without blending and then the transparent geometry with alpha blending. So do you draw the red circle first? – Matthias Aug 27 '18 at 18:21
  • The red circle is also transparent it just looks like it is opaque because it is first. All geometry will be drawn with HSV colors where S and V are 1.0 so hue is the only thing changing. And all geometry is at least somewhat transparent. – J.Doe Aug 27 '18 at 18:25
  • The final image you have shown, depends on the draw order, so do you sort these sprites (red -> blue -> yellow) before drawing? (Alpha blending is not an order-independent transparency technique). – Matthias Aug 27 '18 at 18:28
  • **One thought I had is that some geometry ends up on the exact same z plane so if alpha blending does not work on the same z plane that might cause an issue. But I dont think that is a thing.** And of course in this case, sorting does not work. – Matthias Aug 27 '18 at 18:44

1 Answers1

10

Alpha blending is an order-dependent transparency technique. This means that the (semi-)transparent objects cannot be rendered in any arbitrary order as is the case for (more expensive) order-independent transparency techniques.

  1. Make sure your transparent 2D objects (e.g., circle, rectangle, etc.) have different depth values. (This way you can define the draw ordering yourself. Otherwise the draw ordering depends on the implementation of the sorting algorithm and the initial ordering before sorting.)
  2. Sort these 2D objects based on their depth value from back to front.
  3. Draw the 2D objects from back to front (painter's algorithm) using alpha blending. (Of course, your 2D objects need an alpha value < 1 to actually see some blending.)

Your blend state for alpha blending is correct:

// The blend formula is defined as:
// (source.rgb * sourceRGBBlendFactor  )   rgbBlendOperation (destination.rgb * destinationRGBBlendFactor  ) 
// (source.a   * sourceAlphaBlendFactor) alphaBlendOperation (destination.a   * destinationAlphaBlendFactor)
// <=>
// (source.rgba * source.a) + (destination.rgba * (1-source.a))

descriptor.colorAttachments[0].blendingEnabled             = YES;
descriptor.colorAttachments[0].rgbBlendOperation           = MTLBlendOperationAdd;
descriptor.colorAttachments[0].alphaBlendOperation         = MTLBlendOperationAdd;
descriptor.colorAttachments[0].sourceRGBBlendFactor        = MTLBlendFactorSourceAlpha;
descriptor.colorAttachments[0].sourceAlphaBlendFactor      = MTLBlendFactorSourceAlpha;
descriptor.colorAttachments[0].destinationRGBBlendFactor   = MTLBlendFactorOneMinusSourceAlpha;
descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
Matthias
  • 4,481
  • 12
  • 45
  • 84
  • 2
    In swift this gives: << 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; >> – dgmz Mar 03 '20 at 23:34