Cg 编程/Unity/顺序无关透明度
本教程涵盖顺序无关混合。
它延续了“透明度”部分的讨论,并解决了一些标准透明度问题。如果您还没有阅读过本教程,请先阅读。
正如“透明度”部分所述,混合的结果通常(特别是对于标准 Alpha 混合)取决于三角形渲染的顺序,因此如果三角形没有从后到前排序(通常不是),则会导致渲染伪影。术语“顺序无关透明度”描述了各种避免此问题的技术。其中一种技术是顺序无关混合,即使用不依赖于三角形光栅化的顺序的混合方程。有两种基本方法:叠加混合和乘积混合。
叠加混合的标准示例是双重曝光,就像本节中的图像一样:颜色被叠加,以至于不可能(或者至少非常难)说照片拍摄的顺序。叠加混合可以用“透明度”部分中介绍的混合方程来描述
float4 result = SrcFactor * fragment_output + DstFactor * pixel_color;
其中fragment_output
是片段着色器的输出,pixel_color
是帧缓冲区中已有的颜色,而SrcFactor
和DstFactor
由 Unity 的 ShaderLab 语法中的行确定
Blend
{SrcFactor
的代码} {DstFactor
的代码}
对于叠加混合,DstFactor
的代码必须为One
,而SrcFactor
的代码不能依赖于帧缓冲区中的像素颜色;也就是说,它可以是One
、SrcColor
、SrcAlpha
、OneMinusSrcColor
或OneMinusSrcAlpha
。
一个例子是
Shader "Cg 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
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(vertexPos);
}
float4 frag(void) : COLOR
{
return float4(1.0, 0.0, 0.0, 0.2);
}
ENDCG
}
}
}
摄影中乘积混合的一个例子是使用多个均匀灰度滤镜:滤镜放置在相机上的顺序对图像的最终衰减没有影响。在三角形光栅化的意义上,图像对应于在三角形光栅化之前帧缓冲区的内容,而滤镜对应于三角形。
在 Unity 中使用以下行指定乘积混合时
Blend
{SrcFactor
的代码} {DstFactor
的代码}
SrcFactor
的代码必须为Zero
,而DstFactor
的代码必须依赖于片段颜色;也就是说,它可以是SrcColor
、SrcAlpha
、OneMinusSrcColor
或OneMinusSrcAlpha
。使用OneMinusSrcAlpha
作为DstFactor
的代码,用于使用片段的 alpha 分量指定的透明度来衰减背景,是一个典型的例子。
Shader "Cg 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
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(vertexPos);
}
float4 frag(void) : COLOR
{
return float4(1.0, 0.0, 0.0, 0.2);
}
ENDCG
}
}
}
最后,将用于衰减背景的乘积混合和用于添加三角形颜色的叠加混合结合在一个着色器中,将上述两个通道组合起来是很有意义的。如果忽略了三角形网格自身颜色的衰减,这可以被认为是对小透明度(即小的 alpha 值)的 Alpha 混合的一种近似。
Shader "Cg 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
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(vertexPos);
}
float4 frag(void) : COLOR
{
return float4(1.0, 0.0, 0.0, 0.2);
}
ENDCG
}
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
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 vertexPos : POSITION) : SV_POSITION
{
return UnityObjectToClipPos(vertexPos);
}
float4 frag(void) : COLOR
{
return float4(1.0, 0.0, 0.0, 0.2);
}
ENDCG
}
}
}
请注意,这两个通道的顺序很重要:首先衰减背景,然后添加颜色。
恭喜您已经完成本教程。我们已经了解了
- 什么是顺序无关透明度和顺序无关混合。
- 两种最重要的顺序无关混合类型(叠加和乘积)。
- 如何实现叠加混合和乘积混合。
- 如何组合两个通道用于叠加和乘积混合,以实现顺序无关的 Alpha 混合近似。
如果您想了解更多