Unity Shader入门精要学习——透明效果

这篇具有很好参考价值的文章主要介绍了Unity Shader入门精要学习——透明效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

透明效果

1 实现透明效果的两种方法

透明度测试(Alpha Test)

要么完全透明,要么完全不透明。
实现简单,实质上是一种剔除机制,通过将不满足条件(通常使用小于某个阈值来判定,一般使用clip方法)的片元舍弃的方法来达到完全透明效果。这些被舍弃的片元不会再进行任何的处理,也不会对颜色缓冲产生任何影响,其余满足条件的片元则会继续按普通的不透明物体的处理方式继续处理

透明度混合(Alpha Blending)

可以得到真正的透明效果,通过将当前片元的透明度作为混合因子与已经存储在颜色缓冲中的颜色值进行混合来得到新的颜色,以实现透明效果。
!!!但是,如果需要混合,就需要关闭深度写入(如果不关闭需要透明效果的片元的深度写入,则会直接覆盖掉颜色缓冲中已存储的颜色,无法实现透明效果),由此渲染顺序变得非常重要。

unity shader 透明,Shader学习,unity,shader,着色器

2 透明度测试

使用了透明度测试的Shader都应该在SubShader中设置如下三个标签

SubShader
{
	Tags{ "Queue" = "AlphaTest"  "IgnoreProjector" = "true"    "RenderType" = "TransparentCutout" }
	
	Pass
	{
		........
	}
}

示例代码

Shader "Shader Learning/08 Alpha Effect/01 Alpha Test"
{
	Properties
	{
		_Color("Color", Color) = (1, 1, 1, 1)
		_MainTex("Main Tex", 2D) = "white"{}
		_Cutoff("Alpha Cutoff", Range(0, 1)) = 0.5
	}

	SubShader
	{
		//通常使用了透明度测试的Shader都应该在SubShader中设置这三个标签
		Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "true" "RenderType" = "TransparentCutout" }
		
		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;
			};

			v2f vert(a2v v)
			{
				v2f o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

				o.worldPos = mul(_Object2World, v.vertex).xyz;

				o.worldNormal = UnityObjectToWorldNormal(v.normal);

				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);   //如果小于设定的_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);
			}

			ENDCG
		}
	}

	FallBack "Transparent/Cutout/VertexLit"

}

3 透明度混合

使用了透明度混合的Shader都应该在SubShader中设置如下三个标签,同时关闭深度写入,并设置混合模式

SubShader
{
	Tags { "Queue" = "Transparent" "IgnoreProjector" = "true" "RenderType" = "Transparent" }
	
	Pass
	{
		........
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha
		........
	}
	
}

示例代码

Shader "Shader Learning/08 Alpha Effect/02 Alpha Blend"
{
	Properties
	{
		_Color("Color", Color) = (1, 1, 1, 1)
		_MainTex("Main Tex", 2D) = "white"{}
		_AlphaScale("Alpha Scale", Range(0, 1)) = 1
	}

	SubShader
	{
		//通常使用了透明度混合的Shader都应在SubShader中设置这三个标签
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "true" "RenderType" = "Transparent" }
		
		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }

			ZWrite Off  //关闭深度写入,透明度混合中都应关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha   //设置该Pass的混合模式,我们将源颜色(该片元着色器产生的颜色)的混合因子设为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;
			};

			v2f vert(a2v v)
			{
				v2f o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

				o.worldPos = mul(_Object2World, v.vertex).xyz;

				o.worldNormal = UnityObjectToWorldNormal(v.normal);

				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.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);  //返回需要设置透明通道值,只有使用Blend命令打开混合后,这里的设置才有意义,否则这些透明度并不会对片元的透明效果有任何影响
			}

			ENDCG
		}
	}

	//FallBack "Transparent/VertexLit"
}

解决模型网格之间有互相交叉时引起的错误透明效果

unity shader 透明,Shader学习,unity,shader,着色器
使用两个Pass来渲染模型,第一个Pass开启深度写入,但不输出颜色,仅仅是为了把该模型的深度值写入深度缓冲中;第二个Pass进行正常的透明度混合,由于上一个Pass已经得到了逐像素的正确的深度信息,该Pass就可以按照像素级别的深度排序进行透明渲染。
缺点:多使用一个Pass更消耗性能

Shader "Shader Learning/08 Alpha Effect/03 Alpha Blend Zwrite"
{
	Properties
	{
		_Color("Color", 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  //增加一个Pass,开启深度写入,但不输出颜色,目的仅仅是为了把该模型的深度值写入深度缓冲中
		{
			ZWrite On
			ColorMask 0   //ColorMask用于设置颜色通道的写掩码(write mask),如果设为0,则该Pass不写入任何颜色通道,即不会输出任何颜色。
		}

		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }

			ZWrite Off  //关闭深度写入,透明度混合中都应关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha   //设置该Pass的混合模式,我们将源颜色(该片元着色器产生的颜色)的混合因子设为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;
			};

			v2f vert(a2v v)
			{
				v2f o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

				o.worldPos = mul(_Object2World, v.vertex).xyz;

				o.worldNormal = UnityObjectToWorldNormal(v.normal);

				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.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);  //返回需要设置透明通道值,只有使用Blend命令打开混合后,这里的设置才有意义,否则这些透明度并不会对片元的透明效果有任何影响
			}

			ENDCG
		}
	}

	//FallBack "Transparent/VertexLit"
}

4 双面渲染

使用Cull命令来达到双面渲染的效果

4.1 透明度测试的双面渲染

在Pass块中直接使用Cull Off命令关闭渲染剔除即可,这时候就会对正面和背面都渲染

Shader "Shader Learning/08 Alpha Effect/04 Alpha Test Both Sided"
{
	Properties
	{
		_Color("Color", Color) = (1, 1, 1, 1)
		_MainTex("Main Tex", 2D) = "white"{}
		_Cutoff("Alpha Cutoff", Range(0, 1)) = 0.5
	}

	SubShader
	{
		Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "true" "RenderType" = "TransparentCutout" }
		
		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;
			};

			v2f vert(a2v v)
			{
				v2f o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

				o.worldPos = mul(_Object2World, v.vertex).xyz;

				o.worldNormal = UnityObjectToWorldNormal(v.normal);

				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);   //如果小于设定的_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);
			}

			ENDCG
		}
	}

	FallBack "Transparent/Cutout/VertexLit"

}

4.2 透明度混合的双面渲染

透明度混合的双面渲染要更复杂,因为透明度混合要关闭深度写入,这个时候我们无法保证同一个物体的正面和背面图元的渲染顺序,就有可能得到错误的半透明效果。
解决方法:使用两个Pass,一个Pass只渲染背面(Cull Front),第二个Pass只渲染正面(Cull Back),由于Unity是按顺序执行各个Pass的,因此我们可以得到正确的渲染。文章来源地址https://www.toymoban.com/news/detail-580720.html

Shader "Shader Learning/08 Alpha Effect/05 Alpha Blend Both Sided"
{
	Properties
	{
		_Color("Color", 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
		{
			Tags{ "LightMode" = "ForwardBase" }

			Cull Front   //剔除正面来先渲染背面

			ZWrite Off  //关闭深度写入,透明度混合中都应关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha   //设置该Pass的混合模式,我们将源颜色(该片元着色器产生的颜色)的混合因子设为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;
			};

			v2f vert(a2v v)
			{
				v2f o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

				o.worldPos = mul(_Object2World, v.vertex).xyz;

				o.worldNormal = UnityObjectToWorldNormal(v.normal);

				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.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);  //返回需要设置透明通道值,只有使用Blend命令打开混合后,这里的设置才有意义,否则这些透明度并不会对片元的透明效果有任何影响
			}

			ENDCG
		}

		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }

			Cull Back   //剔除背面,渲染正面

			ZWrite Off  //关闭深度写入,透明度混合中都应关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha   //设置该Pass的混合模式,我们将源颜色(该片元着色器产生的颜色)的混合因子设为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;
			};

			v2f vert(a2v v)
			{
				v2f o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

				o.worldPos = mul(_Object2World, v.vertex).xyz;

				o.worldNormal = UnityObjectToWorldNormal(v.normal);

				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.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);  //返回需要设置透明通道值,只有使用Blend命令打开混合后,这里的设置才有意义,否则这些透明度并不会对片元的透明效果有任何影响
			}

			ENDCG
		}
	}

	//FallBack "Transparent/VertexLit"
}

到了这里,关于Unity Shader入门精要学习——透明效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity Shader学习记录(11) ——透明效果的实现方式

    1 透明效果的两种方法 透明是游戏中经常要使用的一种效果。在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道(Alpha Channel)。当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值之外,它还有另一个属性一一透明度。 当透明度

    2024年02月07日
    浏览(35)
  • Unity中的渲染优化技术 -- Shader入门精要学习(15)

    本章中,我们将阐述一些 Unity 中常见的优化技术。这些优化技术都是和渲染相关的,例如,使用批处理、LOD 技术等。 游戏优化不仅是程序员的工作,更需要美工人员在游戏的美术上进行一定的权衡。例如,避免使用全屏的屏幕特效,避免使用计算复杂的 Shader,减少透明混合

    2024年01月18日
    浏览(30)
  • 【UnityShader入门精要学习笔记】第三章(1)Unity Shader介绍

    本系列为作者学习UnityShader入门精要而作的笔记,内容将包括: 书本中句子照抄 + 个人批注 项目源码 一堆新手会犯的错误 潜在的太监断更,有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 从本章节开始我们要学习Shader相关的知识了,诸位看客可能有的

    2024年02月02日
    浏览(49)
  • 【UnityShader入门精要学习笔记】第三章(2)Unity Shader的形式,章节答疑

    本系列为作者学习UnityShader入门精要而作的笔记,内容将包括: 书本中句子照抄 + 个人批注 项目源码 一堆新手会犯的错误 潜在的太监断更,有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 (该系列笔记中大多数都会复习前文的知识,特别是前文知识非

    2024年02月02日
    浏览(39)
  • 《Unity Shader 入门精要》笔记07

    Unity中通常使用两种方法来实现透明效果:第一种是试用 透明度测试(Alpha Test) ,这种方法其实无法得到真正的半透明效果;另一种是 透明度混合(Alpha Blending) 。 由于深度缓冲的存在,可以让不透明物体不考虑他们渲染顺序也能得到正确的排序效果。但是实现透明效果需

    2024年02月07日
    浏览(32)
  • [Unity Shader入门精要]初级篇 代码拆解

    简介: 介绍了Unity Shader入门精要中初级篇包含的所有代码, 通过详细拆解代码 ,一步一步揭晓Shader的原理。 5.2.1 顶点/片元着色器的基本结构 说人话: •第一行是着色器的名字,用大括号{} 包裹后续所有的Shader代码, Shader。 •紧接着是Shader的属性,用大括号{} 包裹

    2024年02月03日
    浏览(31)
  • Unity Shader入门精要 第六章——Unity中的基础光照

    目录 一、标准光照模型(Phong光照模型) 1、环境光  2、自发光 3、漫反射 4、高光反射 (1)Phong模型 (2)Blinn模型 5、光照模型实现方法——逐顶点和逐像素 二、Unity Shader 漫反射光照模型的实现 1、实践:逐顶点 2、实践:逐像素 3、半兰伯特模型 4、漫反射光照模型效果展

    2024年02月04日
    浏览(40)
  • Unity入门精要03---透明效果

    本节知识架构      如果采用了透明度混合即要是实现半透明效果,那么就要关闭深度写入,那么此时渲染顺序就会变得非常非常重要,不然会出现不正确的遮挡效果。具体的分析可见书中解释 一句话概括就是因为没有写入深度,会导致之后读取的时候没有读取到深度,就可

    2024年02月04日
    浏览(50)
  • 《Unity 入门精要》第8章 透明效果

    在 Unity 中,我们通常使用两种方法来实现透明效果: 透明度测试(Alpha Test) 和 透明度混合(Alpha Blending) 。 当我们渲染不透明物体时,我们不需要特别考虑渲染顺序的问题,因为有 深度缓冲(depth buffer,也称 z-buffer) 的存在,它的基本思想是:根据深度缓存中的来判断

    2024年02月10日
    浏览(31)
  • 【Unity Shader Graph URP渲染管线下的自定义半透明效果_半透明案例分享】

    URP的渲染管线下 在项目设置里找到“Graphic” 找到URP Asset文件 索引到Renderer List文件——“ForwardRenderer” 在这个“ForwardRenderer”文件里找到“Add Renderer Feature” 添加一个渲染对象,类似下图:Render Object (Experimental) 如图设置,将“Event”设置成 AfterRenderingSkybox ,然后“Layer M

    2024年02月09日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包