UnityShder学习之旅--透明度

  • 透明效果

渲染模型时控制它的透明通道(Alpha)
透明度: 1:该像素是完全不透明的。 0:该像素完全不会显示
对于不透明物体,不考虑渲染顺序也能得到正确的排序效果。

方法原理结果条件缺陷
透明度测试1.只要一个片元的透明度不满足条件,对应的片元就会被舍弃
2.被舍弃的不会进行任何处理,也不会对颜色缓冲产生任何影响
3.按普通的不透明物体的方式处理
霸道极端的机制
完全透明或者完全不透明
不关闭深度写入效果极端
边缘效果参差不齐,有锯齿
透明度的变换精度导致
透明度混合1.当前片元的透明度作为混合因子,与存储的颜色值混合可以得到真正的半透明效果关闭深度写入,不关闭深度测试

渲染引擎对物体先排序再渲染

1.先渲染所有不透明物体,并开启它们的深度测试和深度写入。
2.半透明物体按距离摄像机距离排序,从后往前开启深度深度测试,关闭深度写入顺序渲染。
第2步骤若遇交叉就有问题。因此尽可能将复杂的模型拆成独立的多个子模型。

  • 透明度测试
/*********************************************************
透明度测试
1.只要一个片元的透明度不满足条件,对应的片元就会舍弃。
2.被舍弃的不会进行任何处理,也不会对颜色缓冲产生影响
3.没有舍弃的按普通不透明物体的处理方式处理
**********************************************************/
Shader"AlphaTest"{
	Properties{
	  _MainTex("Main Tex", 2D) = "white"{}
	  _CutOff("Cut Off", Range(0,1)) = 0 //剔除的判断条件
	  _Color("Color Tint",Color)=(1,1,1,1)
	}
	SubShader{
		//队列透明度测试,忽略Projector投影器的影响,shader分组到TransparentCutout
		Tags{"Queue" = "AlphaTest" "IngoreProjector"="True" "RenderType"="TransparentCutout"}
		Pass{
		   Tags{"LightMode" = "ForwardBase"}
		   CGPROGRAM
		   #pragma vertex vert
		   #pragma fragment frag
		   #include "Lighting.cginc"
		   #include "AutoLight.cginc"
		   #include "UnityCG.cginc"
		   struct a2v{
			float4 vertex:POSITION;
			float3 normal:NORMAL;
			float4 texcoord:TEXCOORD0;
		   };
		   struct v2f{
			float4 pos:SV_POSITION;
			float3 worldPos:TEXCOORD0;
			float3 worldNormal:TEXCOORD1;
			float2 uv:TEXCOORD2;
		   };
		   float4 _Color;
		   sampler2D _MainTex;
		   float4 _MainTex_ST;
		   half   _CutOff;
		   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(i.texcoord, _MainTex);
		   	return o;
		   }
		   fixed4 frag(v2f i):SV_Target{
		     fixed3 wNormal = normalize(i.worldNormal);
		     fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
		     fixed4 texcoord = tex2D(_MainTex, i.uv)
		     clip(texcoord.a - _CutOff); //剔除
		     fixed3 albedo =  texcoord.rgb * _Color.rgb;
		     fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
		     fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wLightdir));
		     fixed3 color = ambient + diffuse;
		     return fixed4(color, 1.0);
		   }
		   ENDCG	
		}
	}
	FallBack "Transparent/Cutout/VertexLit"//内置的
	//保证使用透明度测试的物体可以正确的向其他物体投射阴影
}

在这里插入图片描述

void clip(param) float4 float3…
/// < summary>
/// 如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色
/// < /summary>
/// < param name=""> 裁剪时使用的标量或矢量条件 </ param>
/// void clip(float4 x) if(any(x < 0)) discard // discard:剔除该片元

  • 透明度混合
    混合命令–Blend
混合操作数定义
源颜色S由片元着色器产生的颜色值
目标颜色D从颜色缓冲中读取到的颜色值
混合后的颜色OS、D混合后得到输出的颜色
语义描述
Blend Off关闭混合
Blend SrcFactor DstFactor开启混合,并设置混合因子最终 = 源 * SrcFactor + 目标 * DstFactorBlend SrcAplha OneMinusSrcAlpha
透明度混合
Blend SrcFactor DstFactor,
ScrFactor A DstFactorA
开启混合,并设置混合因子混合因子不同Blend SrcAlpha OneMinusSrcAlpha,One Zero
BlendOp BlendOperation使用BlendOperation对它们进行其他操作BlendOp Min

混合因子

参数因子混合RGB等式
混合因子
混合A等式
混合因子
One1Blend One One
线性减淡
Blend OneMinusDstColor One == Blend One OneMinusSrcColor
滤色
Zero0Blend DstColor Zero
正片叠底相乘
Blend DstColor SrcColor
两倍相乘
SrcColor源颜色值ScrColor的RGB分量ScrColor的A 分量
SrcAlpha源颜色的透明度值A通道
DstColor源颜色值DstColor的RGB分量DstColor的A 分量
DstAlpha源颜色值
OneMinusSrcColor1-源颜色结果的RGB分量结果的A分量
OneMinusSrcAlpha1-源颜色的透明度值
OneMinusDstColor1-目标颜色结果的RGB分量结果的A分量
OneMinusDstAlpha1-目标颜色的透明度值

混合操作

操作描述等式例子
Add混合后的源、目标颜色相加O = Src * Srbg + Dst * DrgbBlendOp Add
Sub混合后的源颜色减去混合后的目标颜色O = Src * Srgb - Dst* Drgb
RevSub混合后的目标颜色-混合后的源颜色O = DstDrgb - Src Srgb
Min使用源颜色和目标颜色中较小的值,逐分量比较O = min(Sr,Dr),min(Sg,Dg)变暗
BlendOp Min
Blend One One
Max使用源颜色和目标颜色中较大的值,逐分量比较O = max(Sr,Dr),max(Sg,Dg)变亮
BlendOp Max
Blend One One

混合类型
在这里插入图片描述

/*********************************************************
透明度混合
1.使用混合命令 Blend
**********************************************************/
Shader"AlphaBlend"{
	Properties{
	_Color("Color Tint", Color) = (1,1,1,1)
	_MainTex("Main Tex", 2D) = "white"{}
	_AlphaScale("Alpha Scale", Range(0,1)) = 0//控制整体的透明度
	}
	SubShader{
		Tags{"Queue" = "Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			ZWrite Off //关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha //开启混合模式,得到合适的半透明效果
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			struct a2v{
				float4 vertex :POSITION;
				float3 normal:NORMAL;
				float4 texcoord:TEXCOORD0;
			};
			
			struct v2f{
				float4 pos:SV_POSITION;
				float3 worldPos:TEXCOOR0;
				float3 worldNormal:TEXCOORD1;
				float2 uv:TEXCOORD2;
			};
			float4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			half _AlphaScale;
			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 wNormal = normalize(i.worldNormal);
				fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed4 texcoord =  tex2D(_MainTex, i.uv);
				fixed3 albedo =texcoord .rgb * _Color.rgb;
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENDT.xyz * albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wLightdir));
				fixed3 color = ambient + diffuse;
				return fixed4(color, texcoord.a * _AlphaScale);
			}
			ENDCG
			
		}
	}
	FallBack "Transparent/VertexLit"
}

在这里插入图片描述

  • 半透明效果
/*********************************************************
开启深入写入的半透明效果
1.第一个Pass开启深度写入,但不输出颜色
2.第二个Pass进行正常的透明度混合
**********************************************************/
Shader"AlphaBlendZW"{
	Properties{
		_Color("Color 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"}
		//目的:为了把模型的深度信息写入深度缓冲中,从而剔除模型中被自身遮挡的片元
		Pass{
			ZWrite On  	//开启深度写入
			ColorMask 0	//改Pass不写入任何颜色通道,不输出任何颜色
		}
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			ZWrite Off
			Blend ScrAlpha OneMinusSrcAlpha 
			CGPROGAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			struct a2v{
			  float4 vertex : POSITION;
			  float3 normal: NORMAL;
			  float4 texcoord:
			};
			struct v2f{
			   float4 pos:SV_POSITION;
			   float3 worldPos:TEXCOORD0;
			   float3 worldNormal:TEXCOORD1;
			   float2 uv:TEXCOORD2;
			};
			float4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _AlphaScale;
			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);
			}
			fixed4 frag(v2f i):SV_Target{
			    fixed3 wnormal = normalize(i.worldNormal);
			    fixed3 wlightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
			    fixed4 texcoord = tex2D(_MainTex, i.uv);
			    fixed3 albedo = texcoord.rgb * _Color.rgb;
			    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
			    fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wnormal, wlightdir));
			    fixed3 color = ambient + diffuse;
			    return fixed4(color, texcoord.a * _AlphaScale);	
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

ColorMask :设置颜色通道的写掩码
语义 ColorMask RGB | A | 0 | 其他任何RGBA的组合

  • 双面渲染的透明效果
/*********************************************************
透明度测试的双面渲染
1.Pass中使用Cull指令关闭剔除
*********************************************************/
Shader "AlphaTestBothSize"{	
	properties{
		_Color("Color Tint", Color) = (1,1,1,1)
		_MainTex("Main Tex", 2D) = "white"{}
		_CutOut("Cullout", Range(0,1)) = 0
	}
	SubShader{
		Tags{"Queue"="AlphaTest" "IgnoreProjector" = "True" "RenderType"="TransparentCutout"}
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			Cull Off
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"
			struct a2v{
			   float4 vertex:POSITION;
			   float3 normal:NORMAL;
			   float3 texcoord:TEXCOORD0;
			};
			struct v2f{
			  float4 pos:SV_POSITION;
			  float3 worldNormal:TEXCOORD0;
			  float3 worldPos:TEXCOORD1;
			  float2 uv:TEXCOORD2;
			};
			float4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed _CutOut;
			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 wNormal = normalize(i.worldNormal);
				fixed3 wlightdir = normalize(UnityWorldSpaceLightDir(v.worldPos));
				fixed4 texcoord = tex2D(_MainTex, i.uv);
				Clip(texcoord.a - _CutOut);
				fixed3 albedo = texcoord.rgb * _Color.rgb;
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal, wlightdir));
				fixed3 color = ambient + diffuse;
				return fixed4(color, 1);
			}
			ENDCG
		}
	}
	FallBack "Transparent/Cutout/VertexLit"

}

在这里插入图片描述

Cull 控制需要剔除哪个面的渲染图元
语法:Cull Back | Front | Off
Back:背对摄像机的渲染图元不会被渲染
Front:朝向摄像机的渲染图元不会被渲染
Off:关闭剔除功能

-透明度混合的双面渲染

/*********************************************************
透明度混合的双面渲染
1.第一个Pass只渲染背面
2.第二个Pass只渲染正面
**********************************************************/
Shader"AlphaBlendBothSide"{
	Properties{
	  _Color("Color Tint", Color) = (1,1,1,1)
	  _MainTex("MainTex", 2D) = "white"{}
	  _AlphaScale("Alpha Scale", Range(0,1)) = 0.5
	}
	SubShader{
		Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
		CGINCLUDE
		 #include "Lighting.cginc"
		 struct a2v{
    			float4 vertex:POSITION;
    			float3 normal :NORMAL;
    			float4 texcoord:TEXCOORD0;
   		};
   		struct v2f{
    			float4 pos :SV_POSITION;
    			float3 worldNormal:TEXCOORD0;
    			float3 worldPos:TEXCCOOR1;
    			float2 uv:TEXCOORD2;
   		};
   		float4 _Color;
   		sampler2D _MainTex;
   		float4 _MainTex_ST;
   		fixed _AlphaScale;
   		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 wNormal = normalize(i.worldNormal);
    			fixed3 wLightdir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    			fixed4 texcoord = tex2D(_MainTex, i.uv);
    			fixed3 albedo = texcoord.rgb * _Color.rgb;
    			fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    			fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(wNormal,wLightdir));
    			fixed3 color = ambient + diffuse;
    			return fixed4(color, texcoord.a * _AlphaScale);
   		}		
   		ENDCG
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			ZWrite Off
			Cull Front
			Blend SrcAlpha OneMinusSrcAlpha
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			ENDCG
		}
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			Cull Back
			Blend SrcAlpha OneMinusSrcAlpha
   			CGPROGRAM
   			#pragma vertex vert
   			#pragma fragment frag
   			ENDCG
  		}
	}
	FallBack "Transparent/VertexLit"
}

在这里插入图片描述
总结:

效果缺陷原因
透明测试效果极端,不是完全透明,就是完全不透明边缘参差不齐,有锯齿在边界处纹理的透明度的变化精度
透明度混合半透明若模型本身有复杂的遮挡关系时,会产生错误的透明效果关闭深度入,无法对模型进行像素级别的深度排序
开启深度写入的半透明效果与背景混合,但模型内部不会有半透明效果多使用一个Pass,对性能有影响
透明度测试的双面渲染可以透过镂空区域看到内部渲染结果
透明度混合的双面渲染保证背面总是在正面被渲染之前渲染渲染顺序很重要
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值