Chapter8 透明效果——Shader入门精要学习笔记

一、基本概念

  • 在Unity中通常使用两种方法来实现透明效果
    • 透明度测试(无法达到真正的半透明效果)
    • 透明度混合(关闭了深度写入)

透明度测试

  • 基本原理:设置一个阈值,只要片元的透明度小于阈值,就会被舍弃(不会进行任何处理,也不会对颜色缓冲造成影响);否则,就会按照普通的不透明物体来处理(进行深度测试、深度写入等)
  • 效果极端,要么透明,要么完全不透明

透明度混合

  • 基本原理:使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色
  • 需要关闭深度写入,但没有关闭深度测试——深度缓冲是只读的
    • 为什么关闭深度写入:如果开启,半透明物体在不透明物体前面时,半透明物体会挡住不透明物体,实现不了半透明效果
  • 可以实现半透明效果

二、渲染顺序

  • 对于半透明物体和不透明物体,因为关闭了深度写入,所以应该在不透明物体渲染完后再渲染半透明物体
  • 对于两个半透明物体,应该先渲染远处的,再渲染近处的(不准确)

1.渲染引擎的方法

  • 先渲染所有不透明物体,并开启他们的深度测试和深度写入
  • 把半透明物体按他们的距离摄像机的远近进行排序,再按照从后往前的顺序渲染,开启深度测试,关闭深度写入
    • 会有更加复杂的重叠情况,排序困难

2.Unity的渲染顺序

  • 使用SubShader的 Queue 标签来决定我们的模型将归于哪个渲染队列,使用整数索引来表示每个渲染队列,号小的越早被渲染
    在这里插入图片描述
  • 如果想要通过透明度测试来实现效果,代码:
SubShader{
	Tags{ "Queue" = "AlphaTest"}
	Pass{...}
	}
  • 如果想使用透明度混合
SubShader{
	Tags{ "Queue" = "Transparent"}
	Pass{
		ZWrite Off //关闭深度写入
		...}
	}

三、透明度测试

  • 基本原理:设置一个阈值,只要片元的透明度小于阈值,就会被舍弃(不会进行任何处理,也不会对颜色缓冲造成影响);否则,就会按照普通的不透明物体来处理(进行深度测试、深度写入等)
  • 通常会在片元着色器中使用 clip函数 进行透明度测试
    • 如果给定参数的任何一个分量是负数,则会舍弃当前像素的输出颜色
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Chapter8-AlphaTest"
{
   Properties
   {
		_Color ("Main Tint", Color) = (1,1,1,1)
		_MainTex ("Main Tex", 2D) = "white"{}
		_Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5//用于决定我们调用clip进行透明度测试时使用的判决条件
   }
   SubShader
   {
		Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutoff"}
		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 = 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 worldNormal = normalize(i.worldNormal);
					fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

					fixed4 texColor = tex2D(_MainTex, i.uv);

					//透明度测试
					clip(texColor.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);
				}
				ENDCG
		}
   }
   FallBack "Transparent/Cutout/VertexLit"
}

  • _Cutoff (“Alpha Cutoff”, Range(0,1)) = 0.5 用于决定我们调用clip进行透明度测试时使用的判决条件
  • clip(texColor.a - _Cutoff); 做透明度测试,判断texColor.a - _Cutoff是否为负数,负数的纹理颜色为全透明
    在这里插入图片描述

四、透明度混合

  • 基本原理:使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色
  • 需要使用Unity提供的混合命令 Blend
    在这里插入图片描述
  • 本节中使用的是Blend SrcFactor DstFactor来进行混合,将源颜色混合因子SrcFactor设为SrcAlpha,目标颜色混合因子设为OneMinusSrcAlpha
    • 即混合后的新颜色为
    • D s t C o l o r n e w DstColor_{new} DstColornew = SrcAlpha × SrcColor + (1-SrcAlpha) × D s t C o l o r o l d DstColor_{old} DstColorold
  • ZWrite Off 关闭深度写入
Shader "Custom/Chapter8-AlphaBlend"
{
	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"}
		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;
				};

				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 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);
				}
			ENDCG
		}
	}
	FallBack "Transparent/VertexLit"
}

在这里插入图片描述

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

  • 对于复杂网格的半透明处理,避免错误排序
  • 方法:使用 两个Pass 来渲染模型
    • 第一个开启深度写入,但不输出颜色,仅仅为了把该模型的深度值写入深度缓存中
    • 第二个Pass 进行正常的透明度混合,根据第一个Pass,可以进行像素级别的深度排序
    • 缺点是 多个Pass会造成性能的影响
Shader "Custom/Chapter8-AlphaBlend"
{
	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"}
		Pass
		{
			ZWrite On 
			ColorMask 0
		}
		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;
				};

				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 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);
				}
			ENDCG
		}
	}
	FallBack "Transparent/VertexLit"
}
  • 与透明度混合代码几乎一致,只是增加了一个Pass
Pass
		{
			ZWrite On 
			ColorMask 0
		}
  • ZWrite On 打开深度写入,ColorMask 0 意味着Pass不写入任何颜色通道,不会输出任何颜色
    在这里插入图片描述

六、ShaderLab的混合命令

  • 混合与两个操作数有关:源颜色(SourceColor)和目标颜色(DestinationColor)
    • 源颜色指片元着色器产生的颜色 S
    • 目标颜色指从颜色缓冲中读取到的颜色值 D
    • 混合后的颜色 O
    • 包含了 RGBA四个颜色通道

1.混合等式和参数

  • 将S和D进行混合的等式——混合等式,需要两个,一个用于混合RGB,一个用于混合A
  • 设置混合状态时,即设置等式中的 “操作” 和 “因子”
    • 一共有两个等式(分别用于混合RGB和A)
    • 一个等式里有两个因子(一个与S相乘,一个与D相乘)

在这里插入图片描述

  • 第一个命令中只有两个因子——RGB和A通道用相同的两个因子
    在这里插入图片描述
    混合因子可以是哪些值呢?
    在这里插入图片描述

2.混合操作

  • 可以使用 BlendOp BlendOperation命令
    在这里插入图片描述
    在这里插入图片描述
  • 当使用Min和Max操作时,混合因子不起作用的

3.常见的混合类型(效果)

在这里插入图片描述

七、双面渲染的透明效果

  • 观察到其内部结构
  • 可以使用Cull指令来控制需要剔除哪个面的渲染图元
    • Back:背对相机的渲染图元不会被渲染
    • Front:朝向相机的渲染图元不会被渲染
    • Off:关闭剔除功能
Cull Back | Front | Off

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

  • 在Pass中使用 Cull Off 来关闭剔除功能即可
  • 只在 AlphaTest.shader 里Pass中加一句 Cull Off
    在这里插入图片描述

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

  • 因为关闭了深度写入,如果直接加 Cull Off 的话会造成前后面混乱
  • 所以,写了两个Pass (与AlphaBlend.shader一样)
    • 只在Pass中,第一个Pass只渲染背面 ,添加了Cull Front;第二个只渲染正面 添加了Cull Back
    • SubShader是会按照顺序执行Pass
      在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/760813.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VMware--创建Ubuntu虚拟机

原文网址:VMware--创建Ubuntu虚拟机-CSDN博客 简介 本文介绍VMware创建Ubuntu虚拟机的方法。 VMware是最好用的虚拟机软件,安装方法见: 本文安装当前最新的Ubuntu的LTS镜像:ubuntu2022.04.4LTS。 1.下载Ubuntu镜像 下载地址…

电脑技巧:告别卡顿,迎接流畅——Wintune系统优化软件功能详解

目录 一、Wintune介绍 二、Wintune核心功能介绍 2.1 系统优化 2.2 隐私功能 2.3 文件管理模块 2.4 可选选项 2.5 UWP app服务 2.6 startup Manager 2.7、主机编辑 三、总结 电脑是大家目前日常办公娱乐必不可小的工具,软件市场上的系统优化软件层出不穷&a…

一二三应用开发平台应用开发示例(5)——列表视图、树视图、树表视图、树参照视图配置

列表视图 接下来进入列表视图配置,创建的操作方式跟前面相同,如下图所示: 保存后回到列表,点击行记录的配置按钮,进入如下配置页面 可以看到该配置界面相比新增、修改、查看那三个视图要复杂得多,配置项…

帕金森患者的福音,这些食物竟有神奇疗效!

在忙碌的现代生活中,健康问题越来越受到大家的关注。而帕金森病作为一种常见的老年神经系统疾病,更是让许多患者和家庭倍感压力。但是,你知道吗?除了药物治疗和手术干预,日常饮食也能对帕金森病产生积极的影响。今天&a…

开源分享:一套完整的直播购物系统源码

直播购物已经成为一种炙手可热的电商模式,吸引了无数商家和消费者的目光。对于开发者来说,构建一个功能齐全、用户体验优良的直播购物系统是一项复杂的任务。本文将分享一套完整的直播购物系统源码,帮助开发者快速搭建自己的直播购物平台。 …

基于springboot+vue+uniapp的语言课学习系统小程序

开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…

在Centos上安装Lua不要用什么curl指令,这样获取到的压缩包不是gzip格式的

Lua 环境安装 | 菜鸟教程 (runoob.com) 在这一篇里,把这一行 换成 wget http://www.lua.org/ftp/lua-5.3.0.tar.gz 再去解压编译安装就对了。

ue5导航网格设置

AI使用导航网格进行移动,所以,先设置导航网格边界体积 2,使导航网格边界体积覆盖AI所需要的场景(绿色区域),x,y,z在这里都扩大到原来的10倍 3,打开actor的“启用tick并开始” 4&…

No module named ‘MySQLdb‘

python 运行代码的时候遇到No module named ‘MySQLdb’报错如何解决? 解决办法 如果没有安装可以先安装以下依赖库 pip install PyMySQL如果已经安装了PyMySQL,仍然报MySQLdb模块找不到,可以尝试安装以下依赖库。 pip install mysqlclient

二轴机器人装箱机:重塑物流效率,精准灵活,引领未来装箱新潮流

在现代化物流领域,高效、精准与灵活性无疑是各大企业追求的核心目标。而在这个日益追求自动化的时代,二轴机器人装箱机凭借其较佳的性能和出色的表现,正逐渐成为装箱作业的得力助手,引领着未来装箱新潮流。 一、高效:重…

【12】交易-“未花费交易输出”

1. 未花费交易输出 1.1 概念 未花费交易输出(unspent transactions output, UTXO)。未花费(unspent)指的是这个输出还没有被包含在任何交易的输入中,或者说没有被任何输入引用。 在交易结构示意图中,未花费的输出是:tx1, output 1;tx3, output 0;tx4, output 0。 1…

JavaScript原型对象和对象原型、原型继承、原型链

目录 1. 原型对象和对象原型2. 原型继承3. 原型链 1. 原型对象和对象原型 作用: 以前通过构造函数实例化的对象,每个实例化的对象的属性和方法都是独立的,会造成内存浪费。通过prototype对象原型能实现不同实例化对象共享公用的属性和方法,减…

Android 10.0 关于定制自适应AdaptiveIconDrawable类型的动态日历图标的功能实现系列一

1.前言 在10.0的系统rom定制化开发中,在关于定制动态时钟图标中,原系统是不支持动态日历图标的功能,所以就需要从新 定制动态时钟图标关于自适应AdaptiveIconDrawable类型的样式,就是可以支持当改变系统图标样式变化时,动态日历 图标的背景图形也跟着改变,所以接下来就来…

国产分布式数据库灾备高可用实现

最近在进行核心业务系统的切换演练测试,就在想一个最佳的分布式数据库高可用部署方案是如何保证数据不丢、系统可用的,做到故障时候可切换、可回切,并且业务数据的一致性。本文简要介绍了OceanBase数据库和GoldenDB数据库在灾备高可用的部署方…

Springboot ResourceLoader获取指定package目录下所有的类(get class in jar on Linux)

get class in jar on Linux Springboot ResourceLoader获取指定package目录下所有的类 PathMatchingResourcePatternResolver resolver new PathMatchingResourcePatternResolver();String pattern ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX ClassUtils.convertClas…

《概率论与数理统计》期末复习笔记_下

目录 第4章 随机变量的数字特征 4.1 数学期望 4.2 方差 4.3 常见分布的期望与方差 4.4 协方差与相关系教 第5章 大数定律和中心极限定理 5.1 大数定律 5.2 中心极限定理 第6章 样本与抽样分布 6.1 数理统汁的基本概念 6.2 抽样分布 6.2.1 卡方分布 6.2.2 t分布 6.…

join()方法——连接字符串、元组、列表和字典

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 join()方法用于连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串&#…

全球点赞第一起名大师颜廷利:是金子总会“花光”的

在物质世界的繁华背后,隐藏着一个深刻的真理:有形之物的分享会逐渐减少,而无形之物的传递却能不断增值。金钱、货币、银两这些商业领域的实体,往往激发出人类对更多财富的渴望和对资源枯竭的恐惧。这种恐惧源于资源的有限性&#…

CSDN写文章时需要上、下标字号怎么输?

上标:​^^,符号中间加字 下标:~~,符号中间加字 前题是用MD编辑器,不然白搭: 我是感觉CSDN这个文本编辑比较拉,非常想吐槽。

10_网络规划和管理

目录 网络拓扑结构 网络拓扑结构分类 层次化局域网模型 建筑物综合布线系统 网络管理命令 其他知识点汇总 网络地址翻译 默认网关 PPP 冲突域和广播域 网络拓扑结构 网络拓扑结构分类 网络拓扑结构按分布范围分类见表 网络拓扑结构按范围分类 网络分类 缩写 分布…