透明的渲染

透明分为两种:透明测试(Alpha Test),透明混合(Alpha blending),其中透明度测试只是根据Alpha通道 阈值把对应的像素discard丢弃,得到的并不是真正的透明!Alpha blending是得到真正的透明。

透明要想正确就不得不说顺序问题,对于不透明的物体由于有Z-Test,Z-buffer记录深度值像素的遮挡等等都会剔除掉,甚至都没什么overdraw,但是透明物体就不一样了要把Z-Test、Z-write 关闭,导致没有顺序!顺序问题一直是困扰图形界的一大难题,特别是为了能真正透明渲染出来,对于有自遮挡、自相交、循环重叠、A与B有交集等等情况需要处理就需要OIT来解决,但是正确与性能开销现在是鱼与熊掌不可兼得,怎么平衡与舍弃在实时渲染中的各大引擎都有不同做法,比如threejs是直接不处理!

透明与不透明物体:

要想让混合在多个物体上工作,我们需要最先绘制最远的物体,最后绘制最近的物体。普通不需要混合的物体仍然可以使用深度缓冲正常绘制,所以它们不需要排序。但我们仍要保证它们在绘制(排序的)透明物体之前已经绘制完毕了。当绘制一个有不透明和透明物体的场景的时候,大体的原则如下:

  1. 先绘制所有不透明的物体。
  2. 对所有透明的物体排序。
  3. 按顺序绘制所有透明的物体。

透明物体不开Z-test与erlay-z ,只有从后往前渲染才能得到正常的!其余的不透明的有遮挡的只需要从前往后渲染
两种:1、透明度测试、2、透明度混合

透明测试:

只要一个片元的透明度不满足条件(通常是小于莫格阈值)与之对应的片元会被舍弃,被舍弃的片元不会做任何的处理,也不会对颜色缓冲有任何的影响;比如在unity中的片元着色器:

// Alpha test
                clip (texColor.a - _Cutoff);
                // Equal to
//              if ((texColor.a - _Cutoff) < 0.0) {
//                  discard;
//              }

透明度混合:

启动混合:

glEnable(GL_BLEND);

混合公式:
在这里插入图片描述

ThreeJs的透明:

threejs里面透明物体渲染本来就有问题的,两种方式,一种是设置renderOrder渲染顺序一种是自己实现渲染流程,第二种实现单独较大要对threejs渲染流程有清晰的认识,然后通过后处理的形式定制自己的渲染流程。blending也可以试试治标不治本,透明渲染问题是threejs一直有的问题。

there.js例子:
http://127.0.0.1:5555/examples/?q=alpha#webgl_materials_blending
http://127.0.0.1:5555/examples/?q=alpha#webgl_materials_blending_custom
http://127.0.0.1:5555/examples/?q=alpha#webgl_materials_physical_transmission
https://threejs.org/manual/#en/transparency

Material属性:

blending     (混合模式)
depthWrite( 渲染此材质是否对深度缓冲区有任何影响)
depthTest  ( 是否在渲染此材质时启用深度测试)

threejs的所有对象都是Object3D,其中 Object3D.renderOrder这个属性值将使得**scene graph(场景图)**中默认的的渲染顺序被覆盖, 即使不透明对象和透明对象保持独立顺序。 渲染顺序是由低到高来排序的,默认值为0。要处理透明光追处理透明物体问题很好,要实时渲染!(threejs的排序是根据场景图中的mesh的排序)

透明引发的性能问题OverDraw:

OverDraw是什么?
Overdraw就是过度绘制,是指在一帧的时间内像素被绘制了多次,理论上一个像素每次只绘制一次是最优的 主要是为了解决GPU端像素填充率和计算量的瓶颈问题。当然,像素填充率,顾名思义就是GPU在每一帧之内,可以向帧缓存写入像素的数量,常常以百万像素每秒(Megapixels per second)或者十亿像素每秒(Gigapixels per second)来衡量。这东西没有一个标准的计算方式,通常按照光栅化单元乘以这个GPU的核心时钟频率来获得。计算量一般以FLOPS来衡量,即每秒可进行浮点数操作指令数量。 而我们知道,每一个像素,它至少要执行一次光栅化,像素着色器,输出合并阶段这三个阶段,考虑像素数量往往远远大于顶点数量,那么降低需要参与渲染的像素数量是性能优化当中的重点之一。

透明:少用透明, 半透明材质; 现在渲染管线一般优化都挺好的啊?我一下能想到的只有半透明会导致overdraw, 后处理一通乱叠OverDraw也会很高,不过后处理性能问题相比半透明特效来说好优化一些, early z pass的时候就做好剔除。

多层透明深度冲突

如图所示:在这里插入图片描述
渲染乱序常见情况:
在这里插入图片描述
在这里插入图片描述

次序无关透明度(Order Independent Transparency, OIT)

实现半透明渲染的通常做法是将在场景不透明物体完成渲染之后,对场景中半透明物体到摄像机的距离进行排序,从距离摄像机最远的(Z值最大)的物体开始逐个叠加渲染,并在渲染中与输出缓冲中的原有颜色进行混合叠加。对于 2D 半透明渲染,这样的实现是足够的,而在 3D 场景中,由于排序基于物体的轴点位置,渲染时会出现以物体为单位的覆盖效果,例如物体间循环覆盖的效果,就无法被正确的渲染。( oit在shader里创建一个链表然后排序混合就完了 红宝书里有完整例子)

如果您的引擎确实需要顶级的透明效果,这里有一些值得研究的技术:
The original 2001 Depth Peeling paper:像素级精细度,但速度不快。
Dual Depth Peeling:小幅改进
桶排序相关的几篇论文。把片段存到数组,在着色器中进行深度排序。
ATI’s Mecha Demo:效果速度俱佳,但实现起来有难度,需要最新的硬件。用链表存储片段。
Cyril Crassin’s variation on the ATI’s technique:实现难度更大

上古时期有叫画家算法:本质上就是从远处往近地绘制物体,这样遮挡九正确啦,有了Z-test 后充分利用硬件的early-z特性,会从近处远处排序物体(在移动端不管是tbr或者tbdr都是一样的),同理适合半透明的混合,本身混合与顺序无关!

在这里插入图片描述
图形库/硬件的局限性及其带来的困难,以及透明度为何如此棘手的原因。回顾过去二十年来与当前硬件相关的一些较为知名的透明技术。
图形库与硬件的限制:
问题的根源在于深度测试和颜色混合的结合。在片元着色器阶段,没有像不透明物体的zbuffer 、Ztest来告诉图形库,哪些像素是完全可见的或半可见的;
原因之一就是没有一个buffer能够存储深度值或者先后顺序,同时像素之间有遮挡关系,因此需要一种方法来存储所有屏幕坐标的所有像素的所在的不同层。

有序透明:
最方便的解决方案是对透明对象进行排序,这样它们要么从最远到最近,或者从最近到最远(相对于相机的位置)进行绘制。 这样,深度测试不会影响那些在更远/更近的对象之后/之前但在更远/更近的对象之上/之下绘制的像素的结果。排序会降低性能消耗很大,并且由于大多数 3D 应用程序都是实时渲染的,当您在每一帧执行排序时,这一点会更加明显。因此,我们将研究与顺序无关的透明技术的世界,并找到一种更适合我们的目的以及我们的管道的技术,这样我们就不必在绘制之前对对象进行排序。
OIT 技术的目标是消除在绘制时对透明对象进行分类的需要。 根据技术的不同,它们中的一些必须对片段进行排序以获得准确的结果,但只有在所有绘制调用都已完成的后期阶段,其中一些不需要排序,但结果是近似的。
为了克服渲染透明表面的限制而发明的一些更先进的技术,明确地使用可以容纳多层的缓冲区(例如链表或 3D 数组,如 [x][y][z] 像素的信息,并且可以在 GPU 上对像素进行排序,通常是因为它的并行处理能力,而不是 CPU。

A buffer区是 1984 年引入的一种计算机图形技术,它将片段数据(包括微多边形信息)的每个像素列表存储在软件光栅化器雷耶斯渲染 中,最初设计用于抗锯齿但也支持透明度。同时,已经有硬件能够通过执行硬件计算来促进这项任务,这是开发人员获得开箱即用透明度的最方便的方式。SEGA Dreamcast是为数不多的在其硬件中实现了自动逐像素半透明排序的控制台之一。

Depth Peeling:

深度剥离方法,出自 NVIDIA,其核心思想是从相机触发,经过 N(可配置)个 PASS 将场景中的半透明物体根据深度分成了 N 层,分别记录每层的颜色和深度,然后再将每层的颜色混合起来。后来 NVIDIA 为了优化剥离性能,又提出了一种在一个 PASS 中同时剥离 最前面一层 和 最后面 的方法,被成为 Dual Depth Peeling。 Depth Peeling 是一种很慢,非常费显存空间(空间分配可确定),但对硬件没什么高要求的 OIT 方法。

开销是需要两张 depth buffer 。渲染过程需要 N 个 pass , N 是半透明的层数。改进的 Dual Depth Peeling 算法需要 N/2+1 个 pass
Depth peeling 可能带来的问题:

  1. 效率降低,且开销不稳定。( pass 数量依赖于相机角度,骨骼动画等)
  2. 方案本身带来的复杂性。(如何判断当前有多少层半透明,遮挡查询?)
  3. 无已有的可参考的产品,只有技术 demo 。

Depth peeling 是近来研究比较热的半透明渲染方案,其中基于链表的 dx11 实现是一个不小的突破。将来有可能成为比较实用的方案。
NVIDIA的算法:
OrderIndependentTransparency
DualDepthPeeling
在这里插入图片描述

Depth Peeling的例子:

Depth Peeling例子

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值