一、前提知识
(1)深度缓存
它的基本思想是:根据深度缓存中的值来判断该片元距离摄像机的距离,当渲染一个片元时,需要把它的深度值和已经存在于深度缓冲中的值进行比较(如果开启了深度测试),如果它的值距离摄像机更远,那么说明这个片元不应该被渲染到屏幕上(有物体挡住了它);否则,这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中(如果开启了深度写入)。
(2)颜色缓存
需要渲染的场景的每一个像素都最终写入该缓冲区,然后由他渲染到屏幕上显示。
(3)渲染队列
Unity为了解决渲染顺序的问题提供了渲染顺序这一解决方案。我们可以使用SubShader的Queue标签来决定我们的模型属于哪一个渲染队列。Unity内部使用一系列的整数索引来表示每一个渲染队列。且索引号越小表示越早被渲染。
![](https://i-blog.csdnimg.cn/blog_migrate/f0bf59c0b37639bcc784f01c9541e778.png)
二、透明度测试
(1)概念
它采用一种“霸道极端”的机制,只要一个片元的透明度不满足条件(通常是小于某个阈值),那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的不透明物体的处理方式来处理它,即进行深度测试、深度写入等
(2)效果
![](https://i-blog.csdnimg.cn/blog_migrate/ec2525b8682e9eddd250977dd9f29495.png)
(3)实现
Shader "Unity Shaders Book/Chapter 8/Alpha Test"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Main Tint",Color) = (1,1,1,1)
//透明度参考值
_Cutoff ("Alpha Cutoff",Range(0,1)) = 0.5
}
SubShader
{
// Queue 设置渲染队列为透明度测试队列 IgnoreProjector 表示是否受投影器(Projectors)的影响 TransparentCutout提前定义的组
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv : TEXCOORD2;
};
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex,i.uv);
//透明度测试
clip(texColor.a - _Cutoff);
//函数实现
//if (texColor.a - _Cutoff < 0.0)
//{
// discard;
// }
//实现光照
//吸收系数
fixed3 albedo = texColor.rgb * _Color.rgb;
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
//漫反射
fixed3 diffuse = _LightColor0.rgb * albedo * max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient + diffuse,1.0);
}
ENDCG
}
}
Fallback "Transparent/Cutout/VertexLit"
}
三、透明度混合
(1)概念
这种方法可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。注意事项:渲染顺序,关闭深度写入
(2)为什么要关闭深度写入?
如果不关闭深度写入,一个半透明表面背后的表面本来可以透过它被我们看到的,但由于深度测试时判断结果是该半透明表面距离摄像机更近,导致后面的表面会被剔除,我们也就无法透过半透明表面看到后面的物体了。
(2)为什么渲染顺序很重要?