Unity Shader透明效果基础知识

前言:

        在unity中主要有两种透明效果的实现,透明度测试和透明度混合,透明度测试比较简单暴力,就是对片元的alpha通道的值进行测试,满足条件就留下该片元,不满足就抛弃该片元,所以在本章中主要讨论第二种---透明度混合。本书主要内容是对UnityShader入门精要的总结。

一、透明度混合与渲染顺序的联系

为什么半透明效果的渲染要打开深度测试而要关闭深度写入?

在渲染不透明物体时,不考虑渲染顺序是因为深度缓冲的存在,它通过深度测试和深度函数来确保物体的前后遮挡关系,而在渲染透明物体时,我们依然要使用深度测试,它将决定一个片元是否应该被留下,但是要关闭深度写入,先解释一下为什么要关闭深度写入,因为如果不关闭深度写入,那么如果一个透明物体比一个不透明物体里摄像机更近的话,那么这个不透明物体的片元就会被抛弃,我们就无法看到不透明的那种效果。回到渲染顺序的问题上,考虑以下这种情况,一个不透明物体A距离摄像机近,一个不透明物体B距离摄像机远,如果先渲染A再渲染B,这个时候A先被写入颜色缓冲,此时再写入B,由于A没有写入深度缓冲,这时B作为不透明物体会通过深度测试写入深度缓冲,那么此时颜色缓冲区的颜色就是B的,A的颜色就会被清空掉。而如果我们先渲染B再渲染A,B会先写入深度缓冲,A将会通过深度测试,但不会写入深度缓冲,深度值依然是B的深度值,但是它的颜色值会根据Blend命令与当前颜色缓冲区的值进行计算,然后写入颜色缓冲区。

深度测试的目的是比较当前片元与深度缓冲中的深度值,如果没有深度测试,那么半透明物体即使被实体遮挡也能看见了;深度写入的目的是将当前片元的深度值写入深度缓存用于和其它片元做比较,半透明的片元的深度值如果写入,比如有两个半透明物体,那么就会出现将离摄像机较远的半透明物体剔除掉,所以,半透明的片元要关闭深度写入。

渲染引擎一般都会先对物体进行排序,再渲染:

首先渲染所有不透明物体,开启深度测试和深度写入,然后渲染所有不透明物体,开启深度测试,但关闭深度写入。

在unity中解决渲染顺序的方法是渲染队列(render queue),用subshader的Queue标签来决定我们的模型将归于哪个渲染队列。

Background is 1000, Geometry is 2000, AlphaTest is 2450, Transparent is 3000 and Overlay is 4000

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

当模型本身就有很复杂的遮挡关系的时候,例如一个复杂的莫比乌斯环,那么就会有各种各样的因为排序作物而产生的错误的半透明效果。解决方案:使用两个pass来渲染模型,第一个pass开启深度写入,但不输出颜色,这样就不会因为关闭了深度写入出现错误的效果,这一步实际上就是渲染一个不透明物体,但是不输出颜色,只有深度值,深度缓冲中的深度值将会变成该物体的深度值,而不输出颜色也就意味着,虽然深度测试通过了,也进行了深度写入,但是依然保留之前不透明物体片元的颜色,如果这里进行了颜色写入就一定会出错,那就和渲染一个透明物体没有区别了。第二个pass关闭深度写入,进行深度测试,这个时候,物体距离相机最近的片段都会通过深度测试,因为在深度缓冲中的深度值已经是该物体距离相机最近的片段的深度值了,两者是相等的,(按道理来说,即使关闭深度测试,效果也不会出错,因为第一步已经进行了深度测试和深度写入,第二个pass就可以把深度测试和深度写入关闭),但是由于第一个pass是关闭了颜色写入的,所以在颜色缓冲区的颜色还是渲染该物体之前的颜色缓冲区,第二个pass就是进行混合计算然后计算混合写入,这种解决方案有两个问题:第一,增加一个pass会对性能有影响,第二,在模型内部之间不会有任何真正的半透明效果,因为,这种方法的渲染实际上就是先对该物体进行一个片段的去留操作,距离相机较远的片元也就是被遮挡的片元要被抛弃,只留下距离相机最近的片元,内部片元会因此被抛弃,也就理所当然不会出现内部的半透明效果。

在第一个pass中使用一个新的渲染命令,ColorMask

这里需要使用 ColorMask 0;

三、unity中的blend命令

Unity官方文档:ShaderLab混合命令

unity中的blend命令除了设置混合的状态,同时也开启了混合,而在其它图形API里,这两个操作是需要分别单独打开的。

Unity中设置混合因子的命令主要有两个

Blend SrcFactor DstFactor:开启混合,并设置了混合因子,源颜色乘以SrcFactor,目标乘以DstFactor,然后两者相加,这个命令默认是相加,当然也可以有别的计算方式,稍后会介绍

Blend SrcFactor DstFactor,SrcFactorA DstFactorA:这个命令与上一个不同的点就是多了一组因子,从字面意思就能看出这个和Alpha通道有关,这个命令用来为RGB通道和Alpha通道设置不同的混合因子。例如RGB需要混合相加,而透明度需要保留源颜色的透明度,那么就可以写成Blend SrcAlpha OneMinusSrcAlpha,One Zero;

混合操作:上面介绍源颜色和目标颜色的默认混合操作是相加的,它们还可以有很多其它操作,命令为BlendOp Operation

还有一个与Min命令对应的Max命令,类似用法。

常见的混合类型:这里模仿ps里的一些效果给出了一些示例

对Alpha通道的单独处理Blend SrcAlpha 1-SrcAlpha,OneMinusDstAlpha One

注意这个单独处理的公式,alpha通道的总和是要叠加到dst的alpha上,结果就是dstA*one+(1-dstA)*srcA;

四、双面渲染

如果一个物体时透明的,那么我们不仅能看到它背后的物体,还应该能看到该物体内部的情况。而之前的情况都无法观察到物体内部和背面,那是因为渲染引擎为了提高效率默认情况下剔除了背面,如果想实现双面渲染就要使用Cull命令。

Cull Back:剔除背面,默认情况下,是该选项

Cull Front:剔除正面

Cull Off:不剔除

对于透明度测试实现双面渲染来说,只需要关闭剔除,关闭剔除以后就不会再剔除背面,这个时候背面就可以进入gpu渲染管线了,但是依然会有深度测试和深度写入,也就是如果离摄像机更近的片元如果通过了深度测试及其它测试,那么距离摄像机更远的背面依然是看不到的,但是如果离摄像机更近的片元没有通过深度测试和alpha测试被抛弃,且背面的面片通过了测试,此时就能看到背面,这就是透明度测试实现的双面渲染的效果,如果没有双面渲染,那么即使离摄像机更近的片元被抛弃,我们也不能看到背面的片元,因为在渲染管线的应用程序阶段,它就因为背面剔除操作而无法进入GPU渲染管线阶段。

对于透明度混合来说,需要使用两个pass,第一个剔除正面,渲染背面,第二个剔除背面,渲染正面,这样的话由于pass是逐个执行的(注意这里讨论的渲染路径都是forwardbase,以后遇到一些其它渲染路径可能就不是逐个执行了),所以背面总会在正面之前渲染。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中的Shader透明度可以通过透明度测试和透明度混合来实现。透明度测试是一种简单的机制,根据片元的透明度来决定是否舍弃该片元。透明度测试的效果通常是完全透明或完全不透明,并且在边缘处可能会有锯齿。透明度混合是一种更复杂的实现方式,它使用当前片元的透明度作为混合因子,与已存储在颜色缓冲中的颜色进行混合,从而得到真正的半透明效果透明度测试不需要关闭深度入,因为它与其他不透明物体的处理方式几乎相同,只是在片元着色器中增加了对透明度的判断和裁剪。而透明度混合需要关闭深度入,这意味着我们必须非常小心物体的渲染顺序。需要注意的是,尽管关闭深度入,但并没有关闭深度测试,这意味着在使用透明度混合渲染一个片元时,仍会将其深度值与当前深度缓冲中的深度值进行比较。如果该片元的深度值距离摄像机更远,那么将不会再次进行深度混合操作。这一点决定了,当一个不透明物体出现在一个透明物体前时,先渲染的不透明物体可以正常地遮挡住透明物体。换句话说,对于透明度混合来说,深度缓冲是只读的。 所以渲染顺序对于实现透明度混合效果非常重要。确保不透明物体在透明物体前渲染,以便正确地遮挡透明物体。这可以通过设置渲染队列或使用透明度排序等方法来实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值