Unity Shader 从未入门到已放弃(七)--初级

透明效果

渲染顺序

Unity为了解决渲染顺序的问题提供了渲染队列这一解决方案。我们可以使用SubShader的Queue标签来决定我们的模型将归于哪个渲染队列。透明度测试AlphaTest,透明度混合Transparent。

透明度测试

      SubShader{
		Tags{"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}//渲染队列设置为AlphaTest,RenderType可以让Unity把这个Shader归入提前定义的组(这里就是TransparentCutout组),以指明该shader是一个使用了透明度测试的shader。IgnoreProjector设为true,则该shader不会受投影器(Projectors)的影响

		Pass{
			Tags{"LightMode" = "ForwardBase"}//定义了正确的LightMode才能得到一些unity内置光照变量,例如_LightColor0

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			#include "Lighting.cginc"

			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _Cutoff; //因为其范围在[0,1]所以用fixed精度存储

			struct a2v {
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 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);//判断texColor.a - _Cutoff是否为负数,若为负数则舍弃该片元输出

				fixed3 albedo = texColor * _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
		}
		
	}

效果图:

透明测试得到的效果很极端,要么完全透明,要么完全不透明,像在物体上挖了一个洞。

 

透明度混合

      SubShader{
		Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}

		Pass{
			Tags{"LightMode" = "ForwardBase"}//定义了正确的LightMode才能得到一些unity内置光照变量,例如_LightColor0

			Zwrite Off //关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha //开启并设置混合模式 目标颜色的混合因子设置为OneMinusSrcAlpha

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			#include "Lighting.cginc"

			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _AlphaScale; 

			struct a2v {
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 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);

				fixed3 albedo = texColor * _Color.rgb;
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));

				return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
			}

			ENDCG
		}
		
	}

透明度混合使用当前片元的透明度作为混合因子,与已存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但是需要我么你关闭深度写入,这使得我们需要非常小心物体的渲染顺序。

效果图:

但当物体的本身有复杂的遮挡关系,或是包含了复杂的非凸网格的时候,就会有各种各样的排序村错误而产生的错误的透明效果。开启深度写入则可以解决这个问题。

开启深度写入的半透明效果

Pass{
    Zwrite On
    ColorMask 0//ColorMask用于设置颜色通道的写掩码 ColorMask为0时,意味着该pass不写入任何颜色通道 即不会输出任何颜色
}

在之前的基础上增加一个Pass,这个Pass开启深度写入,但不输出颜色,它的目的仅仅是为了把该模型的深度值写入深度缓存中。这个方法的缺点是,多使用一个Pass会对性能造成一定的影响。

效果图:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值