这个教程涵盖了各种各样的关于透明纹理贴图的共用,i.e.RGBA 纹理贴图包含了一个A(alpha)部分 是纹理的不透明的值。
它联合了shader的代码关于“Textured sphere”部分的概念,介绍了 “cutaways”和”Transparency”。
如果你没有读过这篇教程,这将会是一个很好的机会来阅读。
让我们开始说明丢弃片段的”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)通常更有效。
“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
如果更多的的关于刚才提到的技术的实际应用,我们不应该结束这个教程。
左边是一个有着半透明的蓝色海洋的地球仪的图片,是我在维基共享中找到的。这里有一些光照(或轮廓增强(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的例子)是对交互式探索的发展是特别有用的。
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