关于与金属混合

About blending with Metal

在WebGL (OpenGL)中,写在下面

gl.blendFuncSeparate (gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);

在Swift金属

descriptor.colorAttachments [0] .isBlendingEnabled = true
descriptor.colorAttachments [0] .rgbBlendOperation = .add
descriptor.colorAttachments [0] .alphaBlendOperation = .add

descriptor.colorAttachments [0] .sourceRGBBlendFactor = .sourceAlpha
descriptor.colorAttachments [0] .sourceAlphaBlendFactor = .oneMinusSourceAlpha
descriptor.colorAttachments [0] .destinationRGBBlendFactor = .one
descriptor.colorAttachments [0] .destinationAlphaBlendFactor = .one

是正确答案吗?

P.S。 我问上面的问题是因为我想将下面的 WebGL 代码修复到 Metal。在WebGL中,混合体现在整体上,而在Metal中,是以描述符为单位进行的,所以我认为两者都是必要的。

function setupRendering(){
    gl.viewport(0, 0, width, height);
    gl.enable(gl.BLEND);
    // alpha blending
    gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
    // blackclear
    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.bindFramebuffer(gl.FRAMEBUFFER, buffers.framebuffer);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  }

function renderMesh() {
    gl.viewport(0, 0, width, height);
    gl.bindFramebuffer(gl.FRAMEBUFFER, buffers[0].framebuffer);
    gl.useProgram(firstProgram);
    webgl.enableAttribute(planeVBO, attLocation, attStride);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, planeIBO);
    gl.uniform2fv(resolution, [width, height]);
    gl.drawElements(gl.TRIANGLES, plane.index.length, gl.UNSIGNED_SHORT, 0);

    // 
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.clearColor(1.0, 1.0, 1.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.useProgram(renderingProgram);
    webgl.enableAttribute(planeVBO, attLocation, attStride);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, planeIBO);

    // 
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, buffers[0].texture);
    gl.uniform1i(renderingUniLocation.textureUnit, 0);
    gl.drawElements(gl.TRIANGLES, plane.index.length, gl.UNSIGNED_SHORT, 0);
  }

最终输出图像

在第一个可绘制对象上禁用帧混合:

let defaultLibrary = mtlDevice.makeDefaultLibrary()
let vertexFunction = defaultLibrary?.makeFunction(name: "textureVertexShader")
let fragmentFunction = defaultLibrary?.makeFunction(name: "textureFragmentShader")
            
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.label = "Drawable Render Pipeline"
pipelineDescriptor.sampleCount = mtkview.sampleCount
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction
    
pipelineDescriptor.colorAttachments[0].pixelFormat = mtkview.colorPixelFormat
// alpha blending
//pipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
//pipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
//pipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
//
//pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
//pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .oneMinusSourceAlpha
//pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .one
//pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .one

我得到了预期的结果:

更新:

我还将可绘制对象的颜色从黑色更改为白色:

fragment float4 simpleFragmentShader(VertexOut vertexIn [[stage_in]],
                                 constant float2 &resolution [[buffer(0)]]) {

    float2 resolution0 = float2(resolution[0], resolution[1]);
    float2 p = (vertexIn.pos.xy) / min(resolution0.x, resolution0.y);

    float cA = smoothstep(0.5, 0.51, length(p));

    float3 colorB = float3(1.0, 1.0, 1.0);

    return float4(colorB, cA);

}