【《Unity Shader入门精要》 提炼总结】(十三)第十三章·透明度测试的Shader实现&透明度混合的Shader实现

 

 

 

本文由@唐三十胖子出品,转载请注明出处。  
文章链接: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仍然会有下图这样的问题

为了解决这样的问题,下一章我们将为了解决这样的问题

开启深度写入且实现正确的半透明效果

下章见:)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值