六 UnityShader透明效果

在之前的中我们并没有关心过物体渲染顺序的问题 。这是因为深度缓冲的存在 。当渲染一个片元时 , 需要把它的深度值与已经存在于深度缓冲中的值进行比较 , 如果它的深度值更大 , 说明有物体挡住了它 , 这个片元就不应该被渲染到屏幕上;反之 , 这个片元就会覆盖掉颜色缓冲中的像素值 , 它的深度值也会更新到深度缓冲中 。也就是说 , 有深度缓冲在 , 即便我们先渲染了前面的物体A , 再渲染了后面的物体B , 也不用担心B会覆盖掉A 。因为已经在深度缓冲中判断出B在A的后面 。
那么进行透明度混合时为什么要关闭深度写入呢?对于一个半透明物体来讲 , 其后面的物体应该是可以透过它看到的 。但如果开启了深度写入 , 距离摄像机更近的透明物体的深度就会覆盖掉后面的物体 。从而后面物体的表面将会被剔除 , 我们也就无法通过透明物体观察到后面的物体了 。
一旦关闭了深度写入 , 事情就会变得复杂起来 。
比如上面这两个物体 , A是半透明物体 , B是不透明物体 。
那么如果是两个半透明物体又会怎样呢?下图中A和B都是半透明物体 。
渲染引擎在渲染前一般会先对物体进行排序 。先渲染所有不透明物体 , 并开启它们的深度测试和深度写入 。然后再把半透明物体按从后往前的顺序进行渲染 , 并开启深度测试 , 关闭深度写入 。尽管如此 , 仍然会有些不理想的情况:
像上面几种无法得到正确排序顺序的情况 , 就只能将物体进行拆分或是让透明通道更加柔和 , 让穿插不是这么明显 。
Unity的渲染队列
Unity为了解决渲染顺序的问题 , 提供了渲染队列这一解决方案 。我们可以在的Tags中决定模型使用哪个渲染队列 。
二、透明度测试
接下来我们实现透明度测试效果 。首先将之前的纹理采样的复制过来 。这里不考虑高光 , 所以将计算高光的部分删掉
Shader "Unlit/AlphaTest"{Properties{_Diffuse("Diffuse",Color) = (1,1,1,1)_Gloss("Gloss",Range(1,256)) = 20_MainTex("MainTex",2D) = "white" {}}SubShader{Tags{"LightMode"="ForwardBase"}LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"fixed4 _Diffuse;float _Gloss;sampler2D _MainTex;float4 _MainTex_ST;struct v2f{float4 vertex: SV_POSITION;fixed3 worldNormal: TEXCOORD0;float2 uv:TEXCOORD1;};v2f vert(appdata_base v){v2f o;// 将顶点坐标从物体空间转换到裁剪空间o.vertex = UnityObjectToClipPos(v.vertex);// 将法线从物体空间转换到世界空间o.worldNormal = UnityObjectToWorldNormal(v.normal);// 计算uv坐标o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);return o;}fixed4 frag(v2f i):SV_Target{// 获取归一化的光源方向const fixed3 worldLight = normalize(_WorldSpaceLightPos0);const fixed3 albedo = tex2D(_MainTex,i.uv).rgb;// 环境光const fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;// 计算漫反射const fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * (0.5*dot(i.worldNormal, worldLight)+0.5);fixed3 color = ambient + diffuse;return fixed4(color, 1);}ENDCG}}}
首先定义一个属性作为透明度测试时的判断条件 , 并在CG中定义与之匹配的变量
【六UnityShader透明效果】_Cutoff("Alpha Cutoff",Range(0,1)) = 0.5

六  UnityShader透明效果

文章插图
在Tags中将渲染队列设置为「」 , 并忽略投影器的影响