跳转到内容

Cg 编程/Unity/顺序无关透明度

来自 Wikibooks,开放世界的开放书籍
“你去了哪里”由 flickr 用户 Ombligotron 上传。标题中的拼写错误指的是雕塑“云门”,又称“豆子”。

本教程涵盖顺序无关混合

它延续了“透明度”部分的讨论,并解决了一些标准透明度问题。如果您还没有阅读过本教程,请先阅读。

“84 – 父子”由 Ben Newton 上传。双重曝光的示例。

顺序无关混合

[编辑 | 编辑源代码]

正如“透明度”部分所述,混合的结果通常(特别是对于标准 Alpha 混合)取决于三角形渲染的顺序,因此如果三角形没有从后到前排序(通常不是),则会导致渲染伪影。术语“顺序无关透明度”描述了各种避免此问题的技术。其中一种技术是顺序无关混合,即使用不依赖于三角形光栅化的顺序的混合方程。有两种基本方法:叠加混合和乘积混合。

叠加混合

[编辑 | 编辑源代码]

叠加混合的标准示例是双重曝光,就像本节中的图像一样:颜色被叠加,以至于不可能(或者至少非常难)说照片拍摄的顺序。叠加混合可以用“透明度”部分中介绍的混合方程来描述

float4 result = SrcFactor * fragment_output + DstFactor * pixel_color;

其中fragment_output是片段着色器的输出,pixel_color是帧缓冲区中已有的颜色,而SrcFactorDstFactor由 Unity 的 ShaderLab 语法中的行确定

Blend {SrcFactor 的代码} {DstFactor 的代码}

对于叠加混合,DstFactor 的代码必须为One,而SrcFactor 的代码不能依赖于帧缓冲区中的像素颜色;也就是说,它可以是OneSrcColorSrcAlphaOneMinusSrcColorOneMinusSrcAlpha

一个例子是

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 的代码必须依赖于片段颜色;也就是说,它可以是SrcColorSrcAlphaOneMinusSrcColorOneMinusSrcAlpha。使用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 混合近似。

进一步阅读

[编辑 | 编辑源代码]

如果您想了解更多

  • 关于着色器代码,您应该阅读“透明度”部分.
  • 关于另一种顺序无关透明度技术,即深度剥离,您可以阅读 Cass Everitt 的技术报告:“交互式顺序无关透明度”,可以在网上获取。

< Cg 编程/Unity

除非另有说明,本页面上的所有示例源代码均归属于公共领域。
华夏公益教科书