本文由@唐三十胖子出品,转载请注明出处。
文章链接:https://blog.csdn.net/iceSony/article/details/84667551
这篇文章将总结和提炼《Unity Shader入门精要》的第八章“透明效果”的内容。
通过这篇文章,你可以知道
1)透明度测试的Shader实现
2)透明度混合的Shader实现
一.透明度测试的Shader实现
实现原理:通常我们在片元着色器中使用clip函数进行透明度测试 clip函数参数:裁剪时使用的标量或矢量条件
我们用到的是一张png图片你可以在这里下载到png图片☞ 传送门
这就是RGBA通道中的alpha通道
完整代码如下(简单的单张纹理应用代码加上剔除条件)
Shader "sony/Shader184" { Properties { _Diffuse("漫反射系数",Color) = (1.0,1.0,1.0,1.0) _MainTex("主纹理",2D) = "white"{} _Cutoff("透明度系数",Range(0,1)) = 0.5 } SubShader { Tags{"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"} Pass { Tags{ "LightMode" = "ForwardBase" } CGPROGRAM #include "lighting.cginc" #pragma vertex vert #pragma fragment frag float4 _Diffuse; sampler2D _MainTex; float4 _MainTex_ST; fixed _Cutoff; struct a2v { float4 pos : POSITION; float3 normal : NORMAL; float4 texcoord:TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float2 uv:TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.pos); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target { float3 worldNormal = i.worldNormal; float3 worldLightDir = UnityWorldSpaceLightDir(worldNormal); fixed4 texColor = tex2D(_MainTex, i.uv); clip(texColor.a - _Cutoff); float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * texColor*max(0, dot(worldNormal, worldLightDir)); return fixed4(ambient + diffuse,1.0); } ENDCG } } Fallback "Transparent/Cutout/VertexLit" }
其中的Tags和之前的不太一样
包含Queue队列标签设置为AlphaTest,IgnoreProjector设为True(不会受到投影的影响) RenderType设置为透明测试
当然其中最关键的一句clip(texColor.a - _Cutoff);
当alhpa系数为0,不剔除任何片元
当系数为0.5的时候
注意我们的图片必须是png,jpg没有效果 = =
二.透明度混合的Shader实现
工作原理:使用当前片元透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合(关闭深度写入,使得我们要小心物体渲染顺序)
和透明度测试clip函数相比,提供了Blend的方式
代码几乎相同,唯一的不同是需要在Pass中设置混合状态
对比效果很明显,完整代码如下
Shader "sony/Shader188" { Properties { _Diffuse("漫反射系数",Color) = (1.0,1.0,1.0,1.0) _MainTex("主纹理",2D) = "white"{} _Cutoff("透明度系数",Range(0,1)) = 0.5 } SubShader { Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Pass { Tags{ "LightMode" = "ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #include "lighting.cginc" #pragma vertex vert #pragma fragment frag float4 _Diffuse; sampler2D _MainTex; float4 _MainTex_ST; fixed _Cutoff; struct a2v { float4 pos : POSITION; float3 normal : NORMAL; float4 texcoord:TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float2 uv:TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.pos); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target { float3 worldNormal = i.worldNormal; float3 worldLightDir = UnityWorldSpaceLightDir(worldNormal); fixed4 texColor = tex2D(_MainTex, i.uv); float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * texColor*max(0, dot(worldNormal, worldLightDir)); return fixed4(ambient + diffuse,texColor.a * _Cutoff); } ENDCG } } Fallback "Transparent/Cutout/VertexLit" }
深度写入 ZWrite Off 关闭
只有设置了Blend SrcAlpha OneMinusSrcAlpha,最后的返回值修改RGBA通道的alpha值
fixed4(ambient + diffuse,texColor.a * _Cutoff);才会生效
事实上透明度混合的shader仍然会有下图这样的问题
为了解决这样的问题,下一章我们将为了解决这样的问题
开启深度写入且实现正确的半透明效果
下章见:)