Cg Programming In Unity Transparent Textures (Wiki翻译自用)


本教程介绍了alpha纹理贴图的各种常见用法,即具有A(alpha)分量的RGBA纹理图像,该分量指定了纹理像素的不透明度。
它将“Textured Spheres” 部分的着色器代码和“Cutaways”部分和“Transparency”部分中引入的概念结合在一起。

丢弃透明片元

让我们从“Cutaways”一节中介绍的丢弃片元开始。请按照“Textured Spheres”部分中所述的步骤进行操作,并使用以下着色器将图像分配到球体的左侧:

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 = UnityObjectToClipPos(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
      }
   }
   Fallback "Unlit/Transparent Cutout"
}

此片元着色器读取RGBA纹理,并将alpha的值和用户指定的阈值比较,如果alpha值小于阈值,则片元被丢弃,并且表面看起来是透明的。
清注意,在某些平台上,尤其是在移动设备上,丢弃指定的速度非常慢,因此Blend通常是更有效的选择。

Blend

“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;
 
         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 = UnityObjectToClipPos(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;
 
         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 = UnityObjectToClipPos(input.vertex);
            return output;
         }

         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, input.tex.xy);  
         }
 
         ENDCG
      }
   }
   Fallback "Unlit/Transparent"
}

请注意,在此特定纹理图像中,所有alpha值为0的纹理像素都是黑色的。 实际上,此纹理图像中的颜色会与其alpha值“预乘”。 (这种颜色也称为“不透明度加权”。)因此,对于此特定图像,我们实际上应为预乘颜色指定混合方程式,以避免在混合方程式中将颜色与其alpha值再次相乘。 因此,着色器的改进(针对此特定的纹理图像)是在两个过程中均采用以下混合规范:

Blend One OneMinusSrcAlpha

与自定义颜色混合

在这里插入图片描述左侧是作者在Wikimedia Commons上发现的具有半透明蓝色海洋的地球图像。有一些照明(或轮廓增强)正在进行,作者没有尝试重现。相反,仅尝试使用以下着色器重现半透明海洋的基本概念,该着色器将忽略纹理贴图的RGB颜色,并根据alpha值将其替换为特定颜色:

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;
 
         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 = UnityObjectToClipPos(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;
 
         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 = UnityObjectToClipPos(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
      }
   }
   Fallback "Unlit/Transparent"
}

当然,向此着色器添加照明和轮廓增强会很有趣。 还可以改变不透明的绿色,以便将纹理颜色考虑在内,例如:

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

它通过乘以2来强调绿色部分,并通过乘以0.5来使红色和蓝色部分变暗。 但是,这会导致过饱和的绿色被钳制到最大强度。 可以通过将绿色分量的差减半到最大强度1来避免这种情况。 该项变为1.0-color.g,一半就是0.5 * (1.0 - color.g),与最大强度的减小距离相对应的值为: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);

在实践中,必须尝试各种颜色转换的可能性。 为此,使用数字着色器属性(例如,上一行中的系数0.5)对于交互式探索可能性特别有用。

总结

本节我们学习了:

  • 如何将丢弃的片段与Alpha纹理贴图结合使用。
  • 如何将Alpha纹理贴图用于混合。
  • alpha纹理贴图如何用于确定颜色。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值