前言
在OpenGL和DX11中渲染例如植被中的叶子通常会用到Alpha测试来渲染不透明的部分,在iOS平台上,利用Metal API同样也能实现渲染部分透明的物体。
什么是Alpha?
alpha通道通常是用来表示颜色的透明度或者这个像素的可见性(RGBA表示一个像素的话,color.a就是Alpha通道)。
Andrew Glassner写的一篇论文更好地阐述了Alpha通道在渲染半透明或不透明物体的应用。
Alpha测试
本文第一种渲染部分透明表面的技术就是Alpha测试。
它允许我们
通过比较透明度是否超过阈值
决定一个片元是否渲染至缓冲区,
并选择性地渲染透明表面。
它通常用于渲染像叶子一样的物体,叶子纹理的alpha通道可以决定是否需要绘画。
fragment half4 texture_fragment_alpha_test(ProjectedVertex vert [[stage_in]],
texture2d<float, access::sample> texture [[texture(0)]],
sampler texSampler [[sampler(0)]])
{
float4 vertexColor = vert.diffuseColor;
float4 textureColor = texture.sample(texSampler, vert.texCoords);
float diffuseIntensity = max(kMinDiffuseIntensity, dot(normalize(vert.normal.xyz), -kLightDirection));
float4 color = diffuseIntensity * textureColor * vertexColor;
if (textureColor.a < kAlphaTestReferenceValue)
discard_fragment();
return half4(color.r, color.g, color.b, vertexColor.a);
}
discard_fragment方法
这个方法是直接丢弃当前的片元/像素,不进行着色,和GLSL中的discard关键字(HLSL中对应clip函数)的功能一致。
纹理中的Alpha通道
执行Alpha测试
在片元着色器中执行alpha测试变得非常直接,如果从纹理上采样出来的像素的alpha值超过某个阈值,就直接丢弃当前的片元(discard_fragment)
float4 textureColor = texture.sample(texSampler, vert.texCoords);
if (textureColor.a < kAlphaTestReferenceValue)
discard_fragment();
Alpha混合
另一种渲染方法是alpha混合。 下面的混合方程是将原像素和目标像素做alpha混合。一般渲染这种半透明的表面都是按离相机的距离由远到近进行渲染。
在管线状态中启用混合(Blend)
MTLRenderPipelineColorAttachmentDescriptor *renderbufferAttachment = pipelineDescriptor.colorAttachments[0];
renderbufferAttachment.blendingEnabled = YES; //启用混合
renderbufferAttachment.rgbBlendOperation = MTLBlendOperationAdd;
renderbufferAttachment.alphaBlendOperation = MTLBlendOperationAdd;
renderbufferAttachment.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
renderbufferAttachment.sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
renderbufferAttachment.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
renderbufferAttachment.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
总结
在移动设备上使用alpha测试应考虑性能问题,tiled-base的GPU架构使用alpha测试会降低渲染的性能。
代码示例下载链接