实时渲染(RealTimeRendering-4thEdition)笔记——5着色基础(下)


实现半透明物体并允许光线穿过他们有很多方法可以实现。对于渲染算法,这一过程可以分为基于光线和基于视线的效果。基于光线的效果可以让穿过的光线减弱或变相,进而导致场景中的其他物体被不同的方式被照亮;基于视线的效果是考虑如何视线半透明物体本身被渲染的方法。这一章节讨论基于视线的最简单的形式实现透明效果,半透明物体会显示成它背面物体颜色削弱后的效果。
一种实现半透明的方式称为 screen-door transparency ,它的思想是将半透明物体填充为棋盘格,如此它背面的物体可以部分可见。这种方案的一个缺点就是在屏幕的一个位置只有一个半透明物体可以产生半透明效果,例如当一个红色半透明一个绿色半透明物体叠加在了蓝色物体上面,只有这三者中的两种颜色可以显示在棋盘格模式中,除此之外棋盘50%的通过比例也是很大的限制,虽然可以用其他大小的棋盘更改这一比例,但是这些方法将会导致棋盘模式在渲染结果中被识别到。
大多透明算法将物体颜色与背景颜色相混合,这种方法基于alpha混合的概念。我们之前提到过,当一个物体渲染在屏幕上时每个像素都会携带RGB和Z深度数值。除此之外,在每个物体覆盖的像素中还会记录下该位置的alpha值,它可以描述物体的不透明度和片元的覆盖范围。1表示完全不透明,0完全透明。当一个肥皂泡覆盖0.75的像素,透光0.9,那么我们应该设定alpha数值为0.75*(1-0.9)=0.075。但是当我们使用了MSAA反锯齿的话,覆盖的问题就不需要考虑,直接设置alpha为0.1即可。

5.5.1 混合顺序

如果能显示半透明效果,那场景最上方的alpha数值必然小于1。每个像素都能在片元着色器中获取到一个RGBA数值,接下来将会使用该位置原始像素值和新的数值进行混合,实现over操作:
在这里插入图片描述
其中下标s表示新渲染的半透明物体颜色数值,d表示该位置原始数值。计算得到的co会替换掉cd,显然当alpha为1时,计算结果就是用cs直接替换之前的颜色。over操作非常适合模拟场景中出现一些半透明物体,并且透过他们可以看将其背后的物体的效果。但是它对一些特殊效果无法实现,例如现实世界透过红色玻璃观察蓝色物体时应当显示为黑色,但是over会将蓝色和红色进行混合产生粉色,实际上这里应当执行乘法操作可能更为合适。这一部分的实现会在第14章节介绍。
加性混合模式additive blending可以很好地用于发光效果,如闪电或火花,这些效果不会减弱后面的像素,而只会使它们变亮使用如下公式:
在这里插入图片描述对于一些烟雾火焰的渲染场景,这个公式会导致颜色饱和的现象。
为了能够正确的完成透明渲染,我们需要在不透明物体绘制之后再渲染透明物体,首先在bleading功能关闭的状态下对不透明物体渲染,之后开启blending使用over公式进行渲染。理论上也可以一直开启混合,不透明物体的alpha数值为1,渲染结果会完全替换之前的颜色,但是这样增加开销,并且没有实际收益。
Zbuffer对于每个像素位置只能记录一个对象的深度信息,如果多个不透明物体叠加在同一个位置,只使用zbuffer将无法处理所有可见的物体。当我们使用over操作的时候,需要按从后到前的顺序一次执行渲染,否则将会导致错误的视觉效果。一种方法是按照物体质心排序,这种方法虽然粗糙但是可以合理的工作,只是在某些特殊场景,这种方法会存在错误,例如当两个模型交错在一起,或者同一个模型在屏幕中自己遮挡自己的情况。尽管如此,因为他的简单快捷,并且不需要额外的内存空间和GPU的特殊支持,执行粗略的排序仍然是一个通用的选择。在执行半透明渲染的时候,一般关闭Z深度的替换操作,也就是正常执行z测试之后,并不会更改新的z数值,更近的半透明物体渲染之后深度仍然保存的是不透明物体在该位置的深度。通过这样方法在相机旋转过程更改了排序顺序,从而仍然可能出现深度冲突,可以使用前曲面和后曲面两次渲染的方式对这种方法进行优化。
over操作可以进一步调整它的公式,让它变为渲染顺序无关的操作,这种混合模式被称为under操作:
在这里插入图片描述
可以看出under操作可以更改当前位置的alpha数值,这是over操作所不具备的,如此后方的平面也会携带alpha数值参与计算,这样后方使用的公式就如同over操作,只是更改了源和目的物体,此外最重要的是这个公式和渲染顺序无关,更改源和目的会得到相同的结果。

5.5.2 顺序无关的半透明

under操作的使用方法之一是把所有半透明物体渲染到一个颜色缓冲区,在最后在把缓冲区的颜色使用over操作输出到不透明物体组成的场景中。除此之外under操作得一个应用就是被称为depth peeling的order-independent transparency(OIT) 算法。他主要思想是使用两个z缓冲并执行多趟渲染完成。首先第一次渲染所有物体会记录下最前方曲面的深度,接下来渲染所有的半透明物体,如果它的深度和记录的深度相同,就把这一颜色输出到颜色缓冲区,之后使用第二层的深度数值替换该位置(即一次peel操作),依次类推不断记录新的深度,每个颜色都是用under操作在颜色缓冲区混合。最后再把颜色缓冲区的颜色over操作叠加到不透明场景中。
在这里插入图片描述
上图是个半透明的模型从左到右分别为三次peel操作获取的各层模型结果。
基于这种方式需要考虑执行peel的操作,一种思路是执行固定次数的peel,还可以提供硬件支持逐个像素记录所需peel次数。执行速度有种优化方法是使用前后分别peel的思路,分别记录深度最小和最大值进行peel,从而让开销变为原先的一半。
Abuffer是使用硬件优化无序半透明渲染的一种方案,通过Abuffer可以记录每个像素位置的多个半透明物体的RGBA,并使用链表将各深度值链接并排序。最后以从后向前的顺序计算出该位置的最终颜色。
加权和weighted sum transparency也是一种顺序无关的技术,并且是一趟渲染实现的方法。在这里插入图片描述
其中数值u表示的就是背景物体在半透明渲染结果的可见性。可以看出公式中完全对物体排列顺序没有要求,但是这种方法对于不透明程度较高的物体渲染结果其实是与现实有所出入的,现实世界中靠前的物体产生颜色更能占据结果的主导地位,如下图所示。在这里插入图片描述

5.5.3 预乘alpha和合成

over操作还可以用于将图片混合或者将物体合成进行渲染,这一过程称为compositing。使用alpha通道形成图片的方法称为matte,它可以使用alpha表示物体的轮廓,形成的图片可以用于混合或者放置到其他背景上。一种使用合成RGBA数据的方式是premultiplied预乘alpha,在使用前直接将alpha数值乘到RGB中,从而让over操作效率更高。使用了反锯齿技术的不透明物体默认也使用了预乘操作。覆盖40%像素的边缘RGB数值会被乘以0.4,这时RGBA会存储为(0.4,0.4,0.4,0.4),与之相反的策略称为unmultiplied alphas,这时会保存为(1,1,1,0.4)。这样会直接存储原始颜色,但是显示之前每次都需要乘以alpha。
与α通道相关的一个概念是色度键控chroma-keying。这是一个来自视频制作的术语,在这个术语中,演员们被安排在一个绿色或蓝色的屏幕上,并与背景混合。在电影工业中,这一过程被称为绿色筛选或蓝色筛选。这里的想法是,一个特定的颜色色调(对于 电影制作)或精确值(对于计算机图形)被指定为透明的;只要检测到背景,就会显示出来。这使得图像只需使用RGB颜色就可以获得轮廓形状;不需要存储alpha。该方案的一个缺点是,对象在任何像素处要么完全不透明,要么透明,即alpha实际上只有1:0或0:0。例如,GIF格式允许将一种颜色指定为透明。

5.6 显示编码

在我们前面所提到的计算过程都是基于所使用的色度数值满足线性的假设。但在实际显示器输出任务中GPU会自动执行pow(x,1/2.2)的操作,这个调整称为伽马校正gamma-correct。这一节主要介绍这一调整的意义所在。
早期数字成像使用阴极射线管CRT,它的电器特性表现为非线性,也就是电压增大后发射的辐射量不会线性增加,而是与一个指数相关呈正比,例如当指数为2,那么像素数值从0.5变为1会让亮度变为4倍。后期当其他成像技术研发成功后都添加了转换电路来模拟这一特性。这就使得正确的使用图片数据应当以如下图的过程进行。
在这里插入图片描述
对于图片纹理存储的色度数值一般已经进行了gamma校正用于直接在屏幕上显示,所以解码过程需要将纹理像素值更改会线性空间用于着色器进行光照计算完成渲染,得到的颜色需要进行gamma校正进行编码输出到framebuffer中,上屏之后校正结果恰好和屏幕所使用的函数相抵消,从而保证屏幕上的亮度给人的感知会是一个线性的结果。如果不使用gamma变换,在一些线性计算的任务中,以及反锯齿的计算任务产生错误的显示效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值