# 透明效果
不透明物体的渲染顺序
# 混合透明效果
# 混合指令
混合指令以 Blend
关键字开始,后面接混合模式。它可以在 SubShader 中使用,也可以在 Pass 中使用.
Blend Off: 关闭混合处理,当 Shader 中没有添加任何混合指令的时候,默认关闭
BlendSrcFactor DstFactor: 开启混合处理,允许自定义混合模式,新渲染出来的图像被称为 Source, 简称 Src, 之前已经绘制完成的图像被称为 Destination. 简称 Dst。SrcFactory 为源混合系数,DstFactory 为目标图像混合系数.
最终的图像的公式如下:
C o l o r _ r g b a = S o u r c e _ r g b a c d o t S r c F a c t o r y + D e s t i n a t i o n _ r g b a c d o t D s t F a c t o r y Color\_{rgba}=Source\_{rgba} \\cdot SrcFactory + Destination\_{rgba}\\cdot DstFactory C o l o r _ r g b a = S o u r c e _ r g b a c d o t S r c F a c t o r y + D e s t i n a t i o n _ r g b a c d o t D s t F a c t o r y
Blend SrcFactory DstFactory,SrcFactoryA DstFactoryA: 与上述类似,但是将 rgb 和 a 通道分开了
C o l o r _ r g b = S o u r c e _ r g b c d o t S r c F a c t o r y + D e s t i n a t i o n _ r g b c d o t D s t F a c t o r y Color\_{rgb}=Source\_{rgb}\\cdot SrcFactory + Destination\_{rgb} \\cdot DstFactory C o l o r _ r g b = S o u r c e _ r g b c d o t S r c F a c t o r y + D e s t i n a t i o n _ r g b c d o t D s t F a c t o r y
C o l o r _ a = S o u r c e _ a c d o t S r c F a c t o r y A + D e s t i n a t i o n _ a c d o t D s t F a c t o r y A Color\_{a}=Source\_{a}\\cdot SrcFactoryA + Destination\_{a} \\cdot DstFactoryA C o l o r _ a = S o u r c e _ a c d o t S r c F a c t o r y A + D e s t i n a t i o n _ a c d o t D s t F a c t o r y A
BlendOp Op: 使用其他操作进行图像混合,而不再只是进行颜色相加.
BlendOpOpColor,OpAlpha, 跟上述指令类似,但是对 rgb 与 a 分别进行不同的操作
# 混合系数
图像混合不能自由编程,但是给于的组合形式比较多
Zero : 数值为 0, 用来让 Source 或 Destination 完全不能通过
One : 数值为 1, 用来让 Source 或 Destination 完全通过
SrcColor : 把 Source 的像素颜色用作混合系数
DstColor : 把 Destination 的像素颜色用作混合系数
SrcAlpha : 把 Source 的 alpha 数值用作混合系数
DstAlpha : 把 Destination 的 alpha 数值用作混合系数
OneMinusSrcColor : 将 Source 的像素颜色反相之后,用作混合系数
OneMinusDstColor
OneMinusSrcAlpha
OneMminusDstAlpha
# 双面渲染的半透明物体
# 介绍
由于透明通道默认关闭了 ZWriter 如果想要双面渲染透明物体,就必要按照正确的顺序来进行渲染,即先渲染背面,再渲染正面。
# 效果
# 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 Shader "Custom/TwoSideTransparent" { Properties { _MainTex ("Texture", 2D) = "white" {} _MainColor ("MainColor(RGB_A)",Color) = (1,1,1,1) } SubShader { Tags { "Queue" = "Transparent" "RenderType"="Opaque" "IgnoreProjector"="True" } //------------------渲染背面------------------------- Pass { Tags{"LightMode"="ForwardBase"} //开启正面剔除 Cull Front ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fwdbase #include "UnityCG.cginc" //声明包含灯光变量的文件 #include "UnityLightingCommon.cginc" struct v2f { float4 pos : SV_POSITION; float4 worldPos : TEXCOORD0; float2 texcoord :TEXCOORD1; float3 worldNormal : TEXCOORD2; }; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _MainColor; v2f vert(appdata_base v) { v2f o; //获取裁剪空间的顶点坐标 o.pos = UnityObjectToClipPos(v.vertex); //获取世界坐标的顶点坐标 o.worldPos = mul(unity_ObjectToWorld, v.vertex); //获取uv坐标 o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); //获取世界坐标下的法线向量 float3 worldNormal = UnityObjectToWorldNormal(v.normal); //归一化 o.worldNormal = normalize(worldNormal); return o; } fixed4 frag(v2f i) : SV_Target{ //获取光源方向 float3 worldLight = UnityWorldSpaceLightDir(i.worldPos.xyz); //归一化 worldLight = normalize(worldLight); //获取光源与法线的夹角(Lambert光照模型) fixed NdotL = saturate(dot(i.worldNormal, worldLight)); //获取UV颜色 fixed4 color = tex2D(_MainTex, i.texcoord); //Lambert公式 color.rgb *= _MainColor.rgb * NdotL * _LightColor0; color.rgb += unity_AmbientSky; //通过_MainColor属性的a分量控制透明度 color.a *= _MainColor.a; return color; } ENDCG } } }
# 透明测试
游戏场景中经常会遇到这种情况,某些部位会完全透明,但其他部分完全不透明 (如,树叶,栅栏等), 如果继续使用透明度混合的方式,在延迟着色渲染路径中物体将无法接受投影,并且凸起的或者重叠的部分也会出现渲染顺序错误的问题。这时候就需要用到 (Alpha Test) 透明测试。
HLSL 提供了 clip
指令,用于在像素着色器中丢弃某些数值小于 0 的像素。但其实 ZWriter 还是开着的。类似于直接渲染,根据透明阈值直接裁剪
# 效果
# 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 Shader "Custom/AlphaTest" { Properties { _MainTex ("Texture", 2D) = "white" {} _AlphaTest("Alpha Test",Range(0,1)) = 0 } SubShader { Tags { "Queue" = "AlphaTest" "RenderType" = "TransparentCutout" "IgnoreProjector" = "True" } Pass { Tags { "LightMode" = "ForwardBase" } Cull Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "UnityLightingCommon.cginc" struct v2f { float4 pos : SV_POSITION; float4 worldPos : TEXCOORD0; float2 texcoord : TEXCOORD1; float3 worldNormal : TEXCOORD2; }; sampler2D _MainTex; float4 _MainTex_ST; fixed _AlphaTest; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos = mul(unity_ObjectToWorld, v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); float3 worldNormal = UnityObjectToWorldNormal(v.normal); o.worldNormal = normalize(worldNormal); return o; } fixed4 frag(v2f i) : SV_Target{ float3 worldLight = UnityWorldSpaceLightDir(i.worldPos.xyz); worldLight = normalize(worldLight); fixed NdotL = saturate(dot(i.worldNormal, worldLight)); fixed4 color = tex2D(_MainTex, i.texcoord); //开始Aplha测试 clip(color.a - _AlphaTest); color.rgb *= NdotL * _LightColor0; color.rgb += unity_AmbientSky; return color; } ENDCG } } }
# 透明测试抗锯齿
如上图所示,是存在锯齿的,主要是因为显卡计算的时候出现了 非透明即不透明
的极端情况,中间不存在渐变。多重采样抗锯齿 (MultiSampling Anti-Aliasing,MSAA)
可以通过在 Pass 中添加 AlphaToMask On 指令开启显卡的 alpha-to-coverage 功能。可以看到锯齿少了很多