Shader入门-------透明效果
发布日期:2021-07-22 10:54:06 浏览次数:9 分类:技术文章

本文共 3786 字,大约阅读时间需要 12 分钟。

Shader入门-------透明效果

前记:深夜写笔记,以后再也不熬夜了,脑壳疼----------mx

基础:在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道。当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值之后,还有另一个属性----透明度,当透明度为1时,像素完全不透明,为0时,像素完全透明

在unity通常有两种方法实现透明效果:一种是透明度测试,这种无法得到真正的的半透明效果;另一种透明度混合。

深度缓存与深度写入:用于解决可见性问题的,它可以决定哪个物体的哪些部分会被渲染在前面,哪些部分会被其他物体遮挡。基本思想是:根据深度缓存中的值来判断该片元距离摄像机的距离;当渲染一个片元时,我们需要把它的深度值和已经存在在深度缓存中的值进行比较(如果开启了深度测试),如果它的值距离摄像机根源,那么说明这个片元不应该被渲染到屏幕上(有物体挡住了它);否则,这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中(如果开启了深度写入)

博主:mx
透明度测试:只要一个片元的透明度不满足条件(通常是小于某个阈值),那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的完全不透明的物体的处理方式处理它,即进行深度测试、深度写入等。透明度测试是不需要关闭深度写入的,它和其他不透明物体最大的不同就是它会根据透明度来舍弃一些片元。产生的效果也很极端要么完全透明、要么完全不透明

透明度混合:能得到真正的半透明效果。它会使用当前片元的透明值作为混合银子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色值。透明度混合需要关闭深度写入。但是透明度混合,没有关闭深度测试。当透明度混合渲染一个片元是,还是会比较它的深度值与当前深度缓冲中的深度值,如果它的深度值距离摄像机更远就不会进行混合操作。需要考虑渲染顺序。

渲染顺序:

为什么渲染顺序很重要:
因为我们关闭了深度写入。为什么要关闭深度写入呢,因为在透明度混合中如果不关闭深度写入,一个半透明物体背后的物体本来是可以被我们看到的,但是由于深度测试时判断结果是该半透明物体距离摄像机更近,导致后面的表面会被剔除,我们无法透过表面看到后面物体。所以关闭深度写入导致渲染顺序变得非常重要。

渲染顺序实例:

实例一:
假设场景有两个物体A和B,A是半透明物体B是不透明物体
①我们先渲染B再渲染A:那么由于不透明物体开启了深度测试和深度写入,而此时深度缓冲中没有任何有效数据,因此B首先会写入颜色缓冲和深度缓冲。随后我们渲染A,透明物体仍然会进行深度测试,因此我们发现和B相比A距离摄像机更近,因此,我们会使用A的透明度来和颜色缓冲中的B的颜色进行混合,得到正确的半透明效果。
②先渲染A,再渲染B。渲染A时,深度缓冲区中没有任何有效数据,因此A直接写入颜色缓冲,但由于对半透明物体关闭了深度写入,因此A不会修改深度缓冲。等到渲染B时,B会进行深度测试,它发现“咦,深度缓冲中还没有人来过,那我就放心地写入颜色缓冲了!”,结果就是B会直接覆盖A的颜色。从视觉上来看,B就出现了A的前面,这是错误的。

在这里插入图片描述

实例二:

假设场景有两个物体A和B,A和B都是半透明物体
①我们先渲染B,再渲染A。那么B会正常写入颜色缓冲,然后A会和颜色缓冲中的B颜色进行混合,得到正确的半透明效果。
②我们先渲染A,再渲染B。那么A会先写入颜色缓冲,随后B会和颜色缓冲中的A进行混合,这样混合结果会完全反过来,看起来就好像B写在A的前面,得到的就是错误的半透明结构。

在这里插入图片描述

渲染引擎一般都会先对物体进行排序,再渲染。常用的方法是:

①先渲染所有不透明的物体,并开启它们的深度测试和深度写入。
②把半透明物体按它们距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但关闭深度写入。
(注意:尽管这样,我们仍有可能得不到正确的半透明效果。比如玄幻重叠的半透明效果总是得不到正确的半透明效果。所以为了减少错误排序的情况,我们可以尽可能让模型是凸面体,并且考虑将复杂的模型拆分成可以独立排序的多个子模型等等)

Unity Shader 的渲染顺序:

Unity为了解决渲染顺序的问题提供了渲染队列这一解决方案。我们可以使用SubShader的Queue标签来决定我们模型将归于哪个渲染队列。Unity在内部使用一系列正数来索引表示每个渲染队列,且索引号越小表示越早被渲染。
在这里插入图片描述

所以,如果我们要通过透明度测试来实现透明效果,代码中应该包含类似下面的代码:

在这里插入图片描述

如果我们要通过透明度混合来实现透明效果,代码中应该包含类似下面的代码:

在这里插入图片描述

(其中ZWrite Off用于关闭深度写入,我们选择把它写在Pass中,我们也可以把它写在SubShader中,这意味着该SubShader下所有Pass都会关闭深度写入。)

博主:mx

透明度测试:
透明度测试函数:
函数:void clip(float4 x); void clip(float3 x); void clip(float2 x); void clip(float1 x); void clip(float x);
参数:裁剪时使用的标量或矢量条件
描述:如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色。相当于判断是否小于0。等同于如下操作:
void clip(float4 x)
{
if (any(x < 0))
discard; //CG的剔除当前像素功能
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

透明度混合:

Unity提供的混合命令Blend:
在这里插入图片描述

(很多初学者,抱怨自己的模型没有任何透明效果,者往往是因为他们没有在Pass中使用Blend命令,一方面是没有设置混合银子,更重要的是,根本没有打开混合模式)

我们使用第二个语义,将源颜色的混合因子设置为SrcFactor设置为SrcAlpha,而目标颜色的混合因子DstFactor设置为OneMinusSrcAlpha,经过混合后新的颜色为:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

博主:mx

开启深度写入的半透明效果
之前我们说过由于关闭深度写入而造成的错误排序的i情况。一种解决方法是使用两个Pass来渲染模型:第一个Pass开启深度写入,但是不输出颜色,它的目的仅仅是为了把该模型的深度值写入到深度缓存中;第二个Pass进行正常的透明度混合,由于上一个Pass已经得到逐像素的正确的深度信息,该Pass就可以按照像素级别的深度排序结果进行透明渲染
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ShaderLab的混合命令

混合和两个操作数有关:源颜色和目标颜色。源颜色,我们用S表示,指的是由片元着色器产生的颜色值;目标颜色,我们用D表示,值得是从颜色缓冲区中读取到的颜色值。对它们进行混合后得到的输出颜色,我们用O表示,它会重新写入到颜色缓冲中。
(需要注意的是,当我们谈及混合中的源颜色、目标颜色和输出颜色时,它们都包含RGBA四个通道的值,而并非仅仅是RGB通道。)
现在,我们已知两个操作数:源颜色S和目标颜色D,想要得到输出颜色O就必须使用一个等式来计算。我们把这个等式称为混合等式。当进行混合时,我们需要使用两个混合等式:一个用于混合RGB通道,一个用于混合A通道。当设置混合状态时,我们实际上设置的就是混合等式中的操作和因子。在默认情况下,混合等式使用的操作都是加操作,我们只需要再设置一下混合因子即可。下表给出了ShaderLab 中设置混合因子的命令:
在这里插入图片描述

(第一个命令只提供了两个因子,这意味着将使用同样的混合因子来混合RGB通道和A通道,即此时SrcFactorA将等于SrcFactor,DstFactorA 将等于DstFactor 。下面就是使用这些因子进行加法混合时使用的混合公式:在这里插入图片描述

)
ShaderLab支持的几种混合因子:
在这里插入图片描述
博主:mx
有时我们希望可以使用不同的参数混合A通道,这时就可以利用Blend SrcFactor DstFactor,SrcFactorA DstFactorA 指令。例如,如果我们想要在混合后,输出颜色的透明度值就是源颜色的透明度,可以使用下面的命令:
在这里插入图片描述

混合操作:

BlendOp BlendOperation,即混合操作命令。ShaderLab支持的混合操作:
在这里插入图片描述
在这里插入图片描述

常见的混合类型:

在这里插入图片描述

得到的效果:

在这里插入图片描述

(需要注意的是,虽然上面使用Min 和 Max 混合操作时仍然设置了混合因子,但实际上它们并不会对结果有任何影响,因为Min 和 Max 混合操作会忽略混合因子。另一点是,虽然上面有些混合模式并没有设置混合操作的种类,但是它们默认就是使用加法操作,相当于设置了BlendOp Add。)

双面渲染的透明效果

如果我们想要得到双边渲染的效果,可以使用Cull指令来控制需要剔除哪一个面的渲染图元。在Unity中,指令的语法如下:
Cull Back | Front | Off
如果设置为Back,那么那些背对着摄像机的渲染图元就不会被渲染,这也是默认情况下的剔除状态:如果设置为Front,那么那些朝向摄像机的渲染图元就不会被渲染;如果设置为Off,就会关闭剔除功能,那么所有的渲染图元都会被渲染,但由于这时需要渲染的图元数目会成倍增加。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

博主:mx

转载地址:https://blog.csdn.net/m0_56399931/article/details/116361373 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Shader效果------渐变透明
下一篇:Shader入门-------基础纹理

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年03月03日 02时33分17秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

递归字符串逆序 java_在Java中使用递归反转字符串 2019-04-21
java推送功能实现原理图_IOS 基于APNS消息推送原理与实现(JAVA后台) - 图文 2019-04-21
java streamencoder_[求助]关于apcche与tomcat 2019-04-21
golang mongodb mysql_分享一个golang+mongodb+vuejs开发的博客程序 gocms 2019-04-21
hive java insert_hive表insert报错 2019-04-21
java 调试dll jna_Java调用dll的实现,JNA框架 | 学步园 2019-04-21
ios php上传视频文件_IOS上传图片 PHP服务器接收并上传 2019-04-21
php redis zrevrange,Redis Zrevrange 命令 2019-04-21
php利用word模板导出excel文件,php生成导出word doc和excel文件实例 2019-04-21
java 边缓存边播放,java动态缓存技术:WEB缓存应用 2019-04-21
php云盘匿名,PHP7之匿名类 2019-04-21
matlab数据大小不兼容,MATLAB无法执行赋值,因为左侧的索引与右侧的大小不兼容。 求解... 2019-04-21
editor.md使用php,editor.md 配置参数和使用方法 2019-04-21
python mod,mod_python的安装 2019-04-21
python分析彩票数据,这波太炸了!Python脚本可视化居然可以这么玩 2019-04-21
简单的mysql重置root密码,重置mysql的root密码最简单的方法 2019-04-21
用matlab仿真mmc环流抑制器,一种基于准PR控制原理的MMC阀组环流抑制方法 2019-04-21
oracle 排序的分析函数,Oracle SQL:使用分析排序函数 2019-04-21
oracle direct for hdfs xi下载,ORACLE连接HDFS有个专项的解决方案 2019-04-21
java 403怎么抛出_java – 如何在Spring MVC中返回403禁止? 2019-04-21