GLSL 编程/Unity/顺序无关透明度
本教程涵盖顺序无关混合。
它继续讨论“透明度”部分,并解决标准透明度的一些问题。如果你没有读过那个教程,你应该先读一下。
如“透明度”部分所述,混合结果通常(特别是对于标准 alpha 混合)取决于三角形渲染的顺序,因此如果三角形没有从后到前排序(它们通常没有),就会导致渲染伪像。术语“顺序无关透明度”描述了各种避免此问题的技术。其中一项技术是顺序无关混合,即使用不依赖于三角形光栅化顺序的混合方程。有两种基本可能性:叠加混合和相乘混合。
叠加混合的标准示例是本节中的图像中的双重曝光:颜色被添加,以至于不可能(或至少非常困难)说出照片拍摄的顺序。叠加混合可以用“透明度”部分中介绍的混合方程来表征
vec4 result = SrcFactor * gl_FragColor + DstFactor * pixel_color;
其中SrcFactor
和DstFactor
由 Unity 的 ShaderLab 语法中的行确定
Blend
{SrcFactor
的代码} {DstFactor
的代码}
对于叠加混合,DstFactor
的代码必须为One
,SrcFactor
的代码不能依赖于帧缓冲区中的像素颜色;也就是说,它可以是One
、SrcColor
、SrcAlpha
、OneMinusSrcColor
或OneMinusSrcAlpha
。
一个例子是
Shader "GLSL shader using additive blending" {
SubShader {
Tags { "Queue" = "Transparent" }
// draw after all opaque geometry has been drawn
Pass {
Cull Off // draw front and back faces
ZWrite Off // don't write to depth buffer
// in order not to occlude other objects
Blend SrcAlpha One // additive blending
GLSLPROGRAM
#ifdef VERTEX
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3);
}
#endif
ENDGLSL
}
}
}
摄影中相乘混合的一个例子是使用多个均匀的灰色滤镜:滤镜放在相机上的顺序对于图像的最终衰减无关紧要。就三角形的光栅化而言,图像对应于三角形光栅化之前帧缓冲区的内容,而滤镜对应于三角形。
在使用以下行在 Unity 中指定相乘混合时
Blend
{SrcFactor
的代码} {DstFactor
的代码}
SrcFactor
的代码必须为Zero
,DstFactor
的代码必须依赖于片段颜色;也就是说,它可以是SrcColor
、SrcAlpha
、OneMinusSrcColor
或OneMinusSrcAlpha
。一个典型的使用片段的 alpha 分量指定的透明度来衰减背景的示例将使用OneMinusSrcAlpha
作为DstFactor
的代码
Shader "GLSL shader using multiplicative blending" {
SubShader {
Tags { "Queue" = "Transparent" }
// draw after all opaque geometry has been drawn
Pass {
Cull Off // draw front and back faces
ZWrite Off // don't write to depth buffer
// in order not to occlude other objects
Blend Zero OneMinusSrcAlpha // multiplicative blending
// for attenuation by the fragment's alpha
GLSLPROGRAM
#ifdef VERTEX
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3);
// only A (alpha) is used
}
#endif
ENDGLSL
}
}
}
最后,将相乘混合用于衰减背景并将叠加混合用于添加三角形的颜色组合在一个着色器中是有意义的,方法是组合上面介绍的两个通道。如果忽略三角形网格颜色本身的衰减,这可以被认为是对小透明度,即小的 alpha 值的 alpha 混合的近似。
Shader "GLSL shader using order-independent blending" {
SubShader {
Tags { "Queue" = "Transparent" }
// draw after all opaque geometry has been drawn
Pass {
Cull Off // draw front and back faces
ZWrite Off // don't write to depth buffer
// in order not to occlude other objects
Blend Zero OneMinusSrcAlpha // multiplicative blending
// for attenuation by the fragment's alpha
GLSLPROGRAM
#ifdef VERTEX
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3);
// only A (alpha) is used
}
#endif
ENDGLSL
}
Pass {
Cull Off // draw front and back faces
ZWrite Off // don't write to depth buffer
// in order not to occlude other objects
Blend SrcAlpha One // additive blending to add colors
GLSLPROGRAM
#ifdef VERTEX
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#endif
#ifdef FRAGMENT
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3);
}
#endif
ENDGLSL
}
}
}
请注意,两个通道的顺序很重要:首先衰减背景,然后添加颜色。
恭喜你,你已经完成了本教程。我们已经了解了
- 什么是顺序无关透明度和顺序无关混合。
- 两种最重要的顺序无关混合类型是什么(叠加和相乘)。
- 如何实现叠加混合和相乘混合。
- 如何将两个通道组合用于叠加和相乘混合,以实现对 alpha 混合的顺序无关近似。
如果你仍然想了解更多