When I turned on blending, my textures lost their color.

They had a nice hue of grey-blue before. Now they're black and white.

What am I doing wrong?


        pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
        pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.blendAlpha
        pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.oneMinusSourceAlpha
        pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperation.add
        pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.sourceAlpha
        pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.oneMinusSourceAlpha
        pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.add


Those were the flags I'm passing to enable the blending. If I comment out those lines, then I get the color, but not the blending.


Has anyone else encountered this?

Accepted Reply

Oh my god, I just noticed it and figured it out.


Line 11 up there? The RGB source color? I set it to blendAlpha, not sourceAlpha.

Replies

This was the full block of code to set up the pipeline...


        let defaultLibrary = device.newDefaultLibrary()!
        let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment")
        let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex")
      
        let pipelineDescriptor = MTLRenderPipelineDescriptor()
        pipelineDescriptor.vertexFunction = vertexProgram
        pipelineDescriptor.fragmentFunction = fragmentProgram
        pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
      
        pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
        pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.blendAlpha
        pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.oneMinusSourceAlpha
        pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperation.add
        pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.sourceAlpha
        pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.oneMinusSourceAlpha
        pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.add
        pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormat.depth32Float


I thought the pipeline state doesn't change (for a given kind of a thing you are trying to render), so I stored it and reused it. Was that an incorrect assumption?


Edit: I just tried clearing and creating the pipeline descriptor with each rendering pass. Didn't work. And yeah, if I comment out lines 10 through 16 here, the color works, but blending does not.

So I know the alpha channel information has to be at least halfway correct because transparency works when blending is turned on. But then the color gets lost when the blending is turned on. It's like all the pixels got set to solid black or something.

Oh my god, I just noticed it and figured it out.


Line 11 up there? The RGB source color? I set it to blendAlpha, not sourceAlpha.

Hi, Sorry to hijack your thread but I’m having huge problems getting blending working on Metal. I just want to half mix one texture on top of another and my pipeline setup matches yours but the half mixed texture cuts a hole in the background texture. I’ve posted a more compete explanation here: https://stackoverflow.com/q/48569436/372347 Don’t suppose you’d care to share your shader code for this would you? I’m wondering if I’m not doing the blending correctly there.

Perhaps this is due incorrect interpolation? What happens when you use pre-multiplied alpha-blending?

So:

descriptor.colorAttachments[0].sourceAlphaBlendFactor = .one

descriptor.colorAttachments[0].sourceRGBBlendFactor = .one


and in the fragment shader:

return half4(vertex_from_vertex_shader.opacity * colour.r * keyPixel.r, vertex_from_vertex_shader.opacity * colour.g * keyPixel.g, vertex_from_vertex_shader.opacity * colour.b * keyPixel.b, vertex_from_vertex_shader.opacity);

Thanks Darkwing, it was a help! I used your better code but also had to render the primitives in reverse order to the way I had them. Is there not a way to do order-independent blending?

I think the short answer is no. I went back to my red bible and looked at the section in order-independent blending and it’s beyond me for the moment!

Yes, (full) order-independent transparency is highly non-trivial. But you could achieve very decent results by some simple tricks.

Search for example for "Cheap tricks for OpenGL transparency" (Alec's web log).

In general, always draw your opaque objects first.