shader入门精要读书笔记18 透明度测试、透明度混合 及 其他效果实现

一、透明度测试

只要一个片元不满足条件(通常是小于某个阙值),那么它对应的片元就会被舍弃。

函数:
clip(),参数可以是1-4维的矢量,也可以是普通标量。
作用:裁剪使用时的标量或者矢量条件。如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色。

代码:

Shader “Unity Shaders Book/Chapter 8/Alpha Test”
{
	Properties
	{
		_Color("Main Tint",Color)=(1,1,1,1)
		_MainTex("Main Tex",2D)="white"{}
		_Cutooff("Alpha Cutoff",Range(0,1))=0.5	//设置透明度测试使用的判断条件
	}
	Subshader
	{
		Tags{"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"} 
		//这里透明度测试使用的渲染队列为AlphaTest,
		//设置忽视投影器的影响
		//RenderType是可以将Shader提前归入定义的组TransparentCutout,
		//指明这是一个使用了透明度测试的Shader,RenderType通常被用来用于着色器替换功能。
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _Cutoff; //用于判断比较的条件
			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;
			}
			vef vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
				o.worldNormal = UnityObjectToWorldNoraml(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
				renturn 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); //这里直接使用上面的采样后的纹理a分量进行对比_Cutoff。
				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);
			}
		}
	}
	Fallback "Transparent/Cutout/VertexLit"
	//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
	//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}

二、ShaderLab混合命令

混合命令:Blend–混合模式的设置,Unity中Blend命令命令除了设置混合方式,也同时会开启混合,但需要注意在其他图形API中是需要我们手动开启的。

进行混合时,我们需要使用两个混合等式,一个用于混合RGB通道,一个用于A通道。
设置混合状态时,我们设置的就是混合等式中的操作和因子。
两个通道所以可能会用到4个因子。

等式:
RGB: Orgb=SrcFactor×Srgb+DstFactor×Drgb
A: Oa=SrcFactorA×Sa+DstFactorA×Da

语义:

Blend Off 
//关闭混合

Blend SrcFactor DstFactor
//开启混合,源颜色(该片元产生的颜色)乘以SrcFactor,目标颜色(已经存在与颜色缓冲中的颜色)乘以DstFactor,然后两者相加再存入颜色缓冲中。此时,两个通道使用的是相同的混合因子。

Blend SrcFactor DstFactor,SrcFactorA DstFactorA
//和上面一样,只是在透明通道使用了不同的混合因子

BlendOp BlenderOperation
//使用了其他操作(不是简单的加法了)

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
当min与max时,混合因子实际上是不起作用的。他仅仅判断原始的源颜色和目的颜色之间的比较结果
在这里插入图片描述举例:

Blend SrcAlpha OneMinusSrcAlpha,One Zero
//使用源颜色值和(1-原颜色值)作为rgb分量因子,输出颜色透明度值就是源颜色值的透明度

使用其他计算操作(除相加)可见上面变量变暗等效果。

三、透明度混合

实现真正的半透明效果。

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

Shader “Unity Shaders Book/Chapter 8/Alpha Blend”
{
	Properties
	{
		_Color("Main Tint",Color)=(1,1,1,1)
		_MainTex("Main Tex",2D)="white"{}
		_AlphaScale("Alpha Scale",Range(0,1))=1	//控制整体透明度
	}
	Subshader
	{
		Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} 
		//这里透明度混合使用的渲染队列为Transparent,
		//设置忽视投影器的影响
		//RenderType是可以将Shader提前归入定义的组Transparent,
		//指明这是一个使用了透明度混合的Shader,RenderType通常被用来用于着色器替换功能。
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			ZWrite Off  //将深度写入关掉
			Blend SrcAlpha 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;
			}
			vef vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
				o.worldNormal = UnityObjectToWorldNoraml(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
				renturn 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.rgb*_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);//只有打开透明通道后,这里才有意义,否则将不会有影响
			}
		}
	}
	Fallback "Transparent/VertexLit"
	//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
	//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}

四、开启深度写入的透明效果

重新利用深度写入,让模型像半透明物体一样进行淡入淡出。

效果:物体是透明的,但是只看物体时,物体前后之间会有深度效果遮挡。

方法:使用两个Pass来渲染模型,第一个开启深度写入,目的是将模型的深度值写入深度缓冲中,第二个进行透明度混合,因为上一个Pass我们已经得到了逐像素的正确深度信息,该个PASS就可以按照像素级别的深度排序结果进行透明渲染。

缺点:两个PASS会对性能造成一定影响。

代码:

Shader “Unity Shaders Book/Chapter 8/Alpha Blend ZWrite”
{
	Properties
	{
		_Color("Main Tint",Color)=(1,1,1,1)
		_MainTex("Main Tex",2D)="white"{}
		_AlphaScale("Alpha Scale",Range(0,1))=1	//控制整体透明度
	}
	Subshader
	{
		Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} 
		//这里透明度混合使用的渲染队列为Transparent,
		//设置忽视投影器的影响
		//RenderType是可以将Shader提前归入定义的组Transparent,
		//指明这是一个使用了透明度混合的Shader,RenderType通常被用来用于着色器替换功能。
		Pass
		{
			ZWrite On
			ColorMask 0  
			//用于设置颜色通道,设置为0,意味着Pass不写入任何颜色通道,不会输出颜色信息,只是写入深度缓存。
		}
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			ZWrite Off  //将深度写入关掉
			Blend SrcAlpha 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;
			}
			vef vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
				o.worldNormal = UnityObjectToWorldNoraml(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
				renturn 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.rgb*_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);//只有打开透明通道后,这里才有意义,否则将不会有影响
			}
		}
	}
	Fallback "Diffuse"
	//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
	//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}

五、双面渲染的透明效果

效果:可以通过透明部分看到透明物体内部结构和后面结构。

指令:使用剔除Cull指令。
Cull back/Front/Off
设置为Back时,背对摄像机的背面渲染图元不会被渲染,这是默认情况下的剔除状态。
设置为Front时,朝向摄像机的图元不会被渲染。
如果设置为Off,那么所有图元都会被渲染。但这时渲染数目会成倍增加,如不是实现特殊效果不会开启。

1.透明度测试的双面渲染方法:

使用Cull关闭剔除。

Shader “Unity Shaders Book/Chapter 8/Alpha Test Both Sided”
{
	Properties
	{
		_Color("Main Tint",Color)=(1,1,1,1)
		_MainTex("Main Tex",2D)="white"{}
		_Cutooff("Alpha Cutoff",Range(0,1))=0.5	//设置透明度测试使用的判断条件
	}
	Subshader
	{
		Tags{"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"} 
		//这里透明度测试使用的渲染队列为AlphaTest,
		//设置忽视投影器的影响
		//RenderType是可以将Shader提前归入定义的组TransparentCutout,
		//指明这是一个使用了透明度测试的Shader,RenderType通常被用来用于着色器替换功能。
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			Cull off //关闭剔除功能
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _Cutoff; //用于判断比较的条件
			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;
			}
			vef vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
				o.worldNormal = UnityObjectToWorldNoraml(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
				renturn 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); //这里直接使用上面的采样后的纹理a分量进行对比_Cutoff。
				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);
			}
		}
	}
	Fallback "Transparent/Cutout/VertexLit"
	//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
	//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}

2.透明度混合的双面渲染

方法:因为透明度混合需要关闭深度写入,所以使用两个Pass控制渲染顺序,
第一个只渲染背面,第二个只渲染前面。保证背面总是在前面渲染之前进行渲染。

Shader “Unity Shaders Book/Chapter 8/Alpha Blend Both Sided”
{
	Properties
	{
		_Color("Main Tint",Color)=(1,1,1,1)
		_MainTex("Main Tex",2D)="white"{}
		_AlphaScale("Alpha Scale",Range(0,1))=1	//控制整体透明度
	}
	Subshader
	{
		Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} 
		//这里透明度混合使用的渲染队列为Transparent,
		//设置忽视投影器的影响
		//RenderType是可以将Shader提前归入定义的组Transparent,
		//指明这是一个使用了透明度混合的Shader,RenderType通常被用来用于着色器替换功能。
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			Cull Front
			ZWrite Off  //将深度写入关掉
			Blend SrcAlpha 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;
			}
			vef vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
				o.worldNormal = UnityObjectToWorldNoraml(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
				renturn 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.rgb*_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);//只有打开透明通道后,这里才有意义,否则将不会有影响
			}
		}
		Pass
		{
			Tags{"LightMode"="ForwardBase"}
			Cull Back
			ZWrite Off  //将深度写入关掉
			Blend SrcAlpha 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;
			}
			vef vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
				o.worldNormal = UnityObjectToWorldNoraml(v.normal);
				o.worldPos = mul(_Object2World,v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
				renturn 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.rgb*_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);//只有打开透明通道后,这里才有意义,否则将不会有影响
			}
		}
	}
	Fallback "Transparent/VertexLit"
	//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
	//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值