unity3d 内部Transparent (透明)shader 代码
概要· 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.
这个教程涵盖了各种各样的关于透明纹理贴图的共用,i.e.RGBA 纹理贴图包含了一个A(alpha)部分 是纹理的不透明的值。
它联合了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
更多推荐

所有评论(0)