启用混合使 renderPipelineState 无法在 MetalKit MTKView 中构建
Enabling blending makes renderPipelineState fail to build in MetalKit MTKView
我正在 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 的委托中构建管道状态的代码。它从 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]
绑定添加到片段着色器的输出:
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
配置为第一个颜色附件的纹理)。与其 return 构造一个带有 [[color(0)]]
属性的成员,不如从片段函数中 return 一个 float4
(或 half4
),并且该颜色将写入原色附件。但是,一旦您的混合因子配置正确,您编写它的方式应该会起作用。
我正在 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 的委托中构建管道状态的代码。它从 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]
绑定添加到片段着色器的输出:
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
配置为第一个颜色附件的纹理)。与其 return 构造一个带有 [[color(0)]]
属性的成员,不如从片段函数中 return 一个 float4
(或 half4
),并且该颜色将写入原色附件。但是,一旦您的混合因子配置正确,您编写它的方式应该会起作用。