unity3d 内部Transparent (透明)shader 代码


这个教程涵盖了各种各样的关于透明纹理贴图的共用,i.e.RGBA 纹理贴图包含了一个Aalpha)部分 是纹理的不透明的值。

它联合了shader的代码关于“Textured sphere”部分的概念,介绍了 “cutaways”和”Transparency”。

如果你没有读过这篇教程,这将会是一个很好的机会来阅读。

  

丢弃透明片段(Discarding Transparent Fragments

让我们开始说明丢弃片段的”cutaways”部分。按照这些步骤描述的在”Texture Spheres”部分,并把图像分配给材质球的左边根据以下shader 

Shader "Cg texturing with alpha discard" {
   Properties {
      _MainTex ("RGBA Texture Image", 2D) = "white" {} 
      _Cutoff ("Alpha Cutoff", Float) = 0.5
   }
   SubShader {
      Pass {    
         Cull Off // since the front is partially transparent, 
            // we shouldn't cull the back
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         uniform sampler2D _MainTex;    
         uniform float _Cutoff;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            float4 textureColor = tex2D(_MainTex, input.tex.xy);  
            if (textureColor.a < _Cutoff)
               // alpha value less than user-specified threshold?
            {
               discard; // yes: discard this fragment
            }
            return textureColor;
         }
 
         ENDCG
      }
   }
 
   // The definition of a fallback shader should be commented out 
   // during development:
   // Fallback "Unlit/Transparent Cutout"
}


 

 

 

片段着色器读取RGBA贴图并与用户指定的范围值大小比较alpha值。如果 alpha值比范围值小,就丢弃着色片段使之透明。注意: 这项指令在某些平台上是非常缓慢的,特别是在移动设备上。因此,混合(blending)通常更有效。

 

混合(blending

“Transparency”部分描述了怎样用alpha混合去渲染半透明的物体。在这段代码中用RGBA贴图:


Shader "Cg texturing with alpha blending" {
   Properties {
      _MainTex ("RGBA Texture Image", 2D) = "white" {} 
   }
   SubShader {
      Tags {"Queue" = "Transparent"} 
 
      Pass {	
         Cull Front // first render the back faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend SrcAlpha OneMinusSrcAlpha 
            // blend based on the fragment's alpha value
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         uniform sampler2D _MainTex;    
         uniform float _Cutoff;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, input.tex.xy);  
         }
 
         ENDCG
      }
 
      Pass {	
         Cull Back // now render the front faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend SrcAlpha OneMinusSrcAlpha 
            // blend based on the fragment's alpha value
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         uniform sampler2D _MainTex;    
         uniform float _Cutoff;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, input.tex.xy);  
         }
 
         ENDCG
      }
   }
   // The definition of a fallback shader should be commented out 
   // during development:
   // Fallback "Unlit/Transparent"
}

注意 所有的alpha值为0的纹理在这个特别的纹理贴图都是黑色的。事实上,在纹理贴图上的颜色的alpha值是一个”通道(premultiplied )”。(颜色也称为”opacity-weighted”(不透明的权重?))因此,对于这个特殊的纹理贴图,我们实际上应该在这个通道的颜色规定混合(blending)的方程,以便避免在混合(blending)中其他颜色与alpha值相乘。所以,着色器的改进(对于这个特别的纹理贴图)两种情况都是使用下列混合规范:

Blend One OneMinusSrcAlpha

        混合自定义的颜色(Blending with Customized Colors

如果更多的的关于刚才提到的技术的实际应用,我们不应该结束这个教程。

左边是一个有着半透明的蓝色海洋的地球仪的图片,是我在维基共享中找到的。这里有一些光照(或轮廓增强(silhouette enhancement ))正在执行,我不会复制它。取而代之,我只是去复制这个半透明的(semitransparent )蓝色海洋的shader的基本思路,忽略了这个贴图本身的RGB颜色,并用特定的 以alpha值为基础的 颜色替代了它们(这个贴图本身的RGB颜色):

Shader "Cg semitransparent colors based on alpha" {
   Properties {
      _MainTex ("RGBA Texture Image", 2D) = "white" {} 
   }
   SubShader {
      Tags {"Queue" = "Transparent"} 
 
      Pass {	
         Cull Front // first render the back faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend SrcAlpha OneMinusSrcAlpha 
            // blend based on the fragment's alpha value
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         uniform sampler2D _MainTex;    
         uniform float _Cutoff;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            float4 color =  tex2D(_MainTex, input.tex.xy);  
            if (color.a > 0.5) // opaque back face?
            {
               color = float4(0.0, 0.0, 0.2, 1.0); 
                  // opaque dark blue
            }
            else // transparent back face?
            {
               color = float4(0.0, 0.0, 1.0, 0.3); 
                  // semitransparent green
            }
            return color;
         }
 
         ENDCG
      }
 
      Pass {	
         Cull Back // now render the front faces
         ZWrite Off // don't write to depth buffer 
            // in order not to occlude other objects
         Blend SrcAlpha OneMinusSrcAlpha 
            // blend based on the fragment's alpha value
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         uniform sampler2D _MainTex;    
         uniform float _Cutoff;
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            output.tex = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            float4 color = tex2D(_MainTex, input.tex.xy);  
            if (color.a > 0.5) // opaque front face?
            {
               color = float4(0.0, 1.0, 0.0, 1.0); 
                  // opaque green
            }
            else // transparent front face
            {
               color = float4(0.0, 0.0, 1.0, 0.3); 
                  // semitransparent dark blue
            }
            return color;
        }
 
         ENDCG
      }
   }
   // The definition of a fallback shader should be commented out 
   // during development:
   // Fallback "Unlit/Transparent"
}

当然, 它如果在这个shader上加了光照和轮廓增强(silhouette enhancement)会更有趣。一个也能改变透明度的方法,绿色是为了考虑纹理的颜色,举个例子:

color = float4(0.5 * color.r, 2.0 * color.g, 0.5 * color.b, 1.0);

强调绿色部分而乘以2,使红色和蓝色变暗把它们乘以0.5。然而,这个结果是绿色达到了最大的强度而饱和。这个能取绿色部分的1/2来避免使绿色部分达到最大强度1。区分是是 1.0 - color.g 。它的一半是0.5 * (1.0 - color.g)并且这个最大强度1的改化距离的对应的值是:1.0 - 0.5 * (1.0 - color.g)因此,为了避免过于饱和的绿色,我们能用(替代不透明的绿色):

color = float4(0.5 * color.r, 1.0 - 0.5 * (1.0 - color.g), 0.5 * color.b, 1.0);

在实践中,一个是去尝试各种可能性关于像颜色转换等等。在最后,numeric shader properties的应用(举例:上面的0.5的例子)是对交互式探索的发展是特别有用的。

 

 

Summary概要)(不翻译了,就是上面的概要

Congratulations! You have reached the end of this rather long tutorial. We have looked at:

· How discarding fragments can be combined with alpha texture maps.

· How alpha texture maps can be used for blending.

· How alpha texture maps can be used to determine colors.

 

英文原文地址:http://en.wikibooks.org/wiki/Cg_Programming/Unity/Transparent_Textures


翻译by-----wolf96



你可能感兴趣的:(游戏,unity3d,shader)