swifttexturesmetalblending

Replicate OpenGL Blending in Metal


I have been working on porting an open source game written using a fixed function pipeline to Metal.

I have been able to redo all the projection transformation and have things being drawn where they should be drawn with the correct texture and vertex information but I'm having lots of trouble getting the fragment shader to match the OpenGL blending, the textures look correct but the blending and brightness are off.

Here is what I'm trying to match:

GoodRender

here is how it is currently rendering:

enter image description here

The code I can see controlling the GL Blending looks like:

glShadeModel(GL_SMOOTH);

glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);

It draws the main textures with blending disabled then enables it on little triangles (quite visible on my version) between them. There are RGB colors provided for each vertex as well.

There may be other calls altering state but I am not sure what else to look for.

Given all of this I have translated it into two pipeline states one with blending disabled and the other with it enabled. the blending one is set up to look like:

 pipelineStateDescriptor.fragmentFunction = viewer.library.makeFunction(name: "borderFragment")!
    pipelineStateDescriptor.colorAttachments[0].isBlendingEnabled = true

    pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = .add
    pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = .add

    pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
    pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha

    pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
    pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha

Solution

  • I found the problem, it was with how the textures were created, not how the blending was set up which was correct. When creating the textures with MetalKit on one set I used the option: [MTKTextureLoaderOptionSRGB: NSNumber(value:0)] and didn't on the other. When they both were set to be the same (either 1 or 0) they matched and blending worked correctly.

    Shader ended up being:

    fragment float4 terrainFragment(FragmentIn inFrag [[stage_in]],
                                texture2d<float, access::sample> colorTexture [[ texture(0) ]],
                                sampler colorSampler [[ sampler(0) ]]) {
        float4 color = colorTexture.sample(colorSampler, inFrag.uv * 1.33);
        color *= float4(inFrag.shadow,inFrag.shadow,inFrag.shadow,1);
        return color * 4;
    }