swift - 启用混合导致 renderPipelineState 无法在 MetalKit MTKView 中构建

标签 swift metal alphablending depth-buffer metalkit

我正在 Metalkit MTKView 中渲染一个具有一些半透明区域 (alpha < 1) 的几何体。如果在渲染管道状态描述符中将 isBlendingEnabled 保留为 false,则所有内容都会按其应有的方式显示(尽管都是纯色)。

我知道渲染半透明对象取决于绘制顺序。目前,我只想测试 alpha 混合的样子,半透明区域与渲染缓冲区中已有的区域混合,即使它只是混合到背景(此时仍然只是透明颜色)。

但是,当我尝试启用混合时,makeRenderPipelineState 失败并出现以下错误:

Compiler failed to build request Error Domain=CompilerError Code=1 "Fragment shader does not write to render target color(0), index(1) that is required for blending"

这是尝试在 MTKView 委托(delegate)中构建管道状态的代码。当它从 MTKView 继承属性时,我已将这些属性的值放在注释中

do {


let descriptor = MTLRenderPipelineDescriptor()
descriptor.vertexFunction = vertex
descriptor.fragmentFunction = fragment
descriptor.sampleCount = view.sampleCount // 4
descriptor.depthAttachmentPixelFormat = view.depthStencilPixelFormat //.depth32Float

let renderAttachment = descriptor.colorAttachments[0]
renderAttachment?.pixelFormat = view.colorPixelFormat //.bgra8Unorm

// following 7 lines cause makeRenderPipelineState to fail
renderAttachment?.isBlendingEnabled = true
renderAttachment?.alphaBlendOperation = .add
renderAttachment?.rgbBlendOperation = .add
renderAttachment?.sourceRGBBlendFactor = .sourceAlpha
renderAttachment?.sourceAlphaBlendFactor = .sourceAlpha
renderAttachment?.destinationRGBBlendFactor = .oneMinusSourceAlpha
renderAttachment?.destinationAlphaBlendFactor = .oneMinusSource1Alpha

computePipelineState = try device.makeComputePipelineState(function: kernel)
renderPipelineState = try device.makeRenderPipelineState(descriptor: descriptor)

} catch {
    print(error)
}

鉴于错误提示 color(0),我将 color[0] 绑定(bind)添加到片段着色器的输出:

constant float3 directionalLight = float3(-50, -30, 80);

struct FragOut {
    float4 solidColor [[ color(0) ]];
};

fragment FragOut passThroughFragment(Vertex fragIn [[ stage_in ]]) {
    FragOut fragOut;
    fragOut.solidColor = fragIn.color;
    fragOut.solidColor.rgb *= max(0.4, dot(fragIn.normal, normalize(directionalLight)));
    return fragOut;
};

最后,绘制代码:

if let renderPassDescriptor = view.currentRenderPassDescriptor,
    let drawable = view.currentDrawable {
    let commandBuffer = queue.makeCommandBuffer()
    renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.8, green: 0.8, blue: 1, alpha: 1)
    let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
    renderEncoder.setDepthStencilState(depthStencilState)
    renderEncoder.setRenderPipelineState(renderPipelineState)
    //renderEncoder.setTriangleFillMode(.lines)
    renderEncoder.setVertexBuffer(sceneBuffer, offset: 0, at: 0)
    renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, at: 1)           
    renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: Int(vertexCount) ) 

    renderEncoder.endEncoding()
    commandBuffer.present(drawable)
    commandBuffer.commit()
}

我没有在片段着色器中显式设置任何纹理。这是否意味着 currentDrawable 隐式是索引 0 处的颜色附件?为什么错误消息希望在索引 1 处看到 color(0)?混合是否需要两种颜色附件? (它不能只是附加地混合到已经渲染的内容上?)

谢谢。

最佳答案

您似乎无意中调用了dual-source blending 。不要将 destinationAlphaBlendFactor 设置为 oneMinusSource1Alpha,而是尝试 oneMinusSourceAlpha(注意缺少的 1)。

此外,您对 Metal 默认写入第一个颜色附件的直觉是正确的(当前可绘制对象由 MTKView 配置为第一个颜色附件的纹理)。您可以只返回 float4 (或 half4),而不是返回带有 [[color(0)]] 成员的结构体>) 来自片段函数,并且该颜色将被写入原色附件中。但是,一旦正确配置了混合因子,您编写的方式就应该起作用。

关于swift - 启用混合导致 renderPipelineState 无法在 MetalKit MTKView 中构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43727335/

相关文章:

python - 在不同尺寸的两幅图像中进行 Alpha 混合

c++ - Win32 C++ Alphablend 位图部分透明

ios - 为什么我收到此错误 : Ambiguous reference to member 'fetch(with:parse:completion:)'

swift - 如何获取两个 "places"中的firebase数据?

ios - 使用 swift 将 "gif"转换为视频

ios - 在 Swift 中点击按钮时如何防止 uibutton alpha 变为零?

c++ - 按内核线程增量

ios - MTL缓冲区分配+CPU/GPU同步

swift - Metal 计算内核中的 Mipmap 采样器(不是顶点或片段着色器)

delphi - 在 Delphi 中淡入 alpha 混合 PNG 表单