《Unity 入门精要》第8章 透明效果

第8章 透明效果
在 Unity 中,我们通常使用两种方法来实现透明效果:透明度测试(Alpha Test)和透明度混合(Alpha ) 。
当我们渲染不透明物体时,我们不需要特别考虑渲染顺序的问题,因为有深度缓冲(depth ,也称 z-)的存在,它的基本思想是:根据深度缓存中的来判断该片元距离摄像机的距离,当渲染一个片元是,需要把它的深度值和已经存在于深度缓存中的值来做对比,如果它的值距离摄像机更远,那么说明这个片元不应该被渲染到屏幕上;否则,这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中 。
但如果想要实现透明效果,事情就不那么简单了,这是因为,当使用透明度混合时,我们关闭了深度写入(Write) 。
简单来说,透明度测试和透明度混合的基本原理如下:
8.1 为什么渲染顺序很重要
在使用透明度混合时,需要关闭深度写入,此时渲染顺序将变得非常重要 。我们可以思考一下以下几种渲染情况 。
半透明物体 A + 不透明物体 B,A 在 B 前
此种情况有两种渲染顺序:
由此可知,我们应该在渲染完不透明物体后再渲染半透明物体 。
【《Unity 入门精要》第8章 透明效果】A B 均为半透明,A 在 B 前
此种情况有两种渲染顺序:
可以看出,半透明物体之间应该先渲染离摄像机远的物体再渲染近的,才能得到正确的效果 。
循环重叠的半透明物体
基于前面两点,渲染引擎通常会对物体的渲染顺序做一下两点优化:
先渲染所有不透明物体,并开启它们的深度测试和深度写入 。把半透明物体按它们距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但关闭深度写入 。
但就算做了这两点优化,有些时候还是会出现错误的透明效果,比如存在循环重叠的物体:
这是因为深度缓冲中的值其实是像素级别的,即每个像素有一个深度值,但是现在我们对单个物体级别进行排序,这意味着排序结果是,要么物体 A 全部在 B 前面渲染,要么 A 全部在 B 后面渲染 。但如果存在循环重叠的情况,我们永远不可能得到一个正确的排序顺序 。这种时候,我们可以选择把物体拆分成两个部分,然后再进行正确的排序 。但即便我们通过分割的方法解决了循环覆盖的问题,还是会有其他的错误情况 。
无法判定物体排序规则的情况
这里的问题是:如何排序?我们知道,一个物体的网格结构往往占据了空间中的某一块区域,也就是说,这个网格上每一个点的深度值可能都是不一样的,我们选择哪个深度值来作为整个物体的深度值和其他物体进行排序呢?是网格中点吗?还是最远的点?还是最近的点?不幸的是,对于上图中的情况,选择哪个深度值都会得到错误的结果,我们的排序结果总是 A 在 B 的前面,但实际上 A 有一部分被 B 遮挡了 。这也意味着,一旦选定了一种判断方式后,在某些情况下半透明物体之间一定会出现错误的遮挡问题 。这种问题的解决方法通常也是分割网格 。
尽管总是会有一些情况打乱我们的阵脚,但由于上述方法足够有效并且容易实现,因此大多数游戏引擎都使用了这样的方法 。为了减少错误排序的情况,我们可以尽可能让模型是凸面体,并且考虑将复杂的模型拆分成可以独立排序的多个子模型等 。
8.2 Unity中的渲染顺序
Unity 为了解决渲染顺序的问题设计了渲染队列( queue),我们可以使用的 Queue 标签来决定我们的模型将归于哪个渲染队列 。Unity 在内部使用一系列整数索引来表示每个渲染队列,且索引号越小表示越早被渲染,并且Unity提前定义了5个渲染队列: