Metal实现Alpha混合离屏渲染效果异常,OpenGL迁移适配问题求助
我计划将此前在OpenGL上实现的功能迁移到Metal中复现,基于Metal实现离屏渲染,通过Alpha Blending能力实现完整绘制效果,目前遇到渲染结果不符合预期的问题。
- 效果对比:OpenGL端可正常输出边缘平滑的透明圆形效果,Metal端渲染结果边缘出现异常黑边
- 离屏渲染阶段的管线配置如下:
renderToTextureRenderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
- 当前Metal渲染效果:透明背景区域呈现黑色,圆形边缘有明显黑边
上述配置下渲染结果周边变为黑色,若将配置调整为:
MTLClearColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.0)
则整体变为白色,属于可预见的正常表现;如果调整为MTLClearColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.0),渲染结果色彩介于二者之间,但和预期效果差距很大。
就算不设置clearColor渲染结果也一致,可判断该配置不是问题根源,大概率是Shader本身的问题,或是Alpha混合时最终渲染的Pipeline配置问题。其中一个待解决的点是未能在Metal中复现OpenGL最终渲染时的gl.clearColor(1.0, 1.0, 1.0, 1.0);效果,参照官方文档方法尝试也没有成功。
Shader逻辑无特殊配置,是将距离函数生成的圆形作为Alpha值,在Alpha混合和最终渲染阶段作为纹理贴出。
注:由于需要保证Alpha混合的最终效果,不接受在白色背景上渲染红色圆形这类简单实现方案。
问题排查方向及解决方案
结合描述的现象,问题几乎可以确定出在Alpha混合因子配置和纹理采样时的Alpha预乘处理两个环节,可按照以下步骤逐一排查:
- 检查离屏渲染管线的混合配置
Metal默认不会开启Alpha混合,需要手动配置MTLRenderPipelineColorAttachmentDescriptor的相关属性,要复现OpenGL默认的透明混合效果,对应配置如下:
colorAttachment.isBlendingEnabled = true colorAttachment.sourceRGBBlendFactor = .sourceAlpha colorAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha colorAttachment.sourceAlphaBlendFactor = .one colorAttachment.destinationAlphaBlendFactor = .oneMinusSourceAlpha
如果离屏渲染管线没有正确配置上述参数,就会出现ClearColor的RGB值直接和绘制内容叠加的问题,和描述的现象完全吻合。
检查离屏纹理的像素格式
如果离屏纹理使用的是不包含Alpha通道的格式,会导致写入的Alpha值直接丢失,后续采样纹理做最终渲染时自然无法得到正确的透明效果,确认离屏纹理格式使用带Alpha通道的格式即可。检查最终渲染阶段的纹理采样和混合配置
把离屏纹理绘制到MTKView上时,也需要开启正确的Alpha混合,同时要确认Shader输出的颜色值是否和Alpha匹配:如果离屏纹理已经是预乘Alpha的格式,要把混合因子的sourceRGBBlendFactor调整为.one,否则会出现颜色过淡或者偏黑的问题。确认MTKView的clearColor配置
无法复现OpenGL的gl.clearColor(1.0,1.0,1.0,1.0)效果的原因很可能是配置对象错误:MTKView的clearColor是作用在最终渲染到屏幕的渲染通道上,而非离屏渲染通道,需要在绘制离屏纹理到屏幕之前,给当前的渲染通道的colorAttachment设置clearColor为MTLClearColor(red: 1, green: 1, blue: 1, alpha: 1),同时设置loadAction为.clear即可。
内容的提问来源于stack exchange,提问作者x001017

