Unity Shader透明度测试、透明度混合、开启深度写入的半透明效果、双面渲染的透明效果

本文介绍了Unity中实现透明效果的两种主要方法:透明度测试和透明度混合。透明度测试通过舍弃不满足条件的片元实现,不需要关闭深度写入;透明度混合则需关闭深度写入并注意渲染顺序。文章详细阐述了为何透明度混合需关闭深度写入,以及渲染顺序的重要性。此外,还讨论了开启深度写入的半透明效果和双面渲染透明物体的方法,包括代码示例和效果展示。
摘要由CSDN通过智能技术生成

在Unity中,我们通常使用两种方式来实现透明效果:1.使用透明度测试 2.透明度混合.
透明度测试:只要一个片元的透明度不满足条件,它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何英雄,不需要关闭深度写入.
透明度混合: 使用当前片元的透明度作为混合因子,与以及存储在颜色缓冲中的颜色值进行混合,得到新的颜色。需要关闭深度写入,要非常小心物体的渲染顺序.

问题1:在透明度混合中为什么需要关闭深度写入呢?
如果不关闭深度写入,一个透明物体背后的物体本来是可以被我们看到的,但由于深度测试时判断结果是该半透明物体表面距离摄像机更近,导致后面的物体被剔除,也就无法透过透明物体看到后面的物体了。
问题2:在透明度混合中为什么渲染顺序很重要呢?
假设场景里面有物体A和B,A是半透明物体,B是不透明物体,A在B的前面

考虑两种情况:
1.先渲染B,在渲染A:
由于不透明物体开启了深度测试和深度写入,一开始深度缓冲中没有任何数据,B首先会写入颜色缓冲和深度缓冲,然后渲染A,透明物体仍然会进行深度测试,但是A比B距离摄像机更近,因此我们会使用A的透明度和颜色缓冲中的B的颜色进行混合,得到正确的半透明效果.
2.先渲染A,在渲染B:
首先先渲染A,此时深度缓冲中没有任何有效数据,但是由于对半透明物体关闭了深度写入,A不会修改深度缓冲,然后渲染B,B进行深度测试,由于深度缓冲没有发生变化,B就直接写入颜色缓冲和深度缓冲,造成的结果就是B出现在了A的前面.

渲染顺序总结如下:
1.先绘制所有不透明的物体,并开启它们的深度测试和深度写入.
2.对所有透明的物体排序。
3.按从后往前的顺序绘制所有透明的物体。

透明度测试

通常,我们会在片元着色器中使用clip函数来进行透明度测试,如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色.它等同于下面的代码:

void clip(float4 x)
{
   
	if(any(x < 0))
		discard;
}

第一步创建一个Shader,在属性里面添加一个变量_Cutoff用来控制透明度测试时使用的阈值:

_Cutoff("Alpha Cutoff", Range(0, 1)) = 0.5//用于决定调用clip进行透明度测试时使用的判断条件,0-1像素透明度的范围

第二步在SubShader语义块中定义一个Pass语义块:

		Tags{
   "Queue " = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}
		//使用渲染队列名为AlphaTest的队列,RenderType 让Unity把这个shader归入到提前定义的组,以指明该shader是一个使用了
		//透明度测试的shader. ignoreProjector 意味着shader不会受到投影器的影响
		pass
		{
   
			Tags{
   "LightMode" = "ForwardBase"}

第三步在CG代码块中声明对应属性的变量:

fixed _Cutoff;

然后定义顶点着色器的输入和输出结构体:

			struct a2v 
			{
   
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;
			};
			struct v2f
			{
   
				float4 pos : SV_POSITION;
				float3 wordlNormal : TEXCOORD;
				float3 worldPos : TEXCOORD1;
				float2 uv : TEXCOORD2;
			};

接着定义顶点着色器:

			v2f vert(a2v v)
			{
   
				v2f o;
				o.pos =  UnityObjectToClipPos(v.vertex);
				o.wordlNormal = 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.wordlNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed4 texColor = tex2D(_MainTex, i.uv);
				clip (texColor.a - _Cutoff);
				//if((texColor.a - _Cutoff) < 0.0)//检测透明度,如果是负数就舍弃输出
				//{
   
				//	discard;
				//}
				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);
			}

效果如下:
在这里插入图片描述
完整代码如下:

Shader "AlphaTest"
{
   

	Properties
	{
   
		_Color("Color Tint",Color) = (1, 1, 1, 1)
		_MainTex("Main Tex",2D) = "white"{
   }
		_Cutoff("Alpha Cutoff", Range(0, 1)) = 0.5//用于决定调用clip进行透明度测试时使用的判断条件,0-1像素透明度的范围

	}
	SubShader
	
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值