OpenGL复习(MRT、泛光、延迟渲染)
多渲染目标(Multiple Render Targets)MRT
- 帧缓冲可以附加多个颜色纹理附件,一次drawcall输出多张纹理图片
泛光
- 模拟光源向四周发散出光晕,使得渲染的场景看起来更亮更真实
- 实现方式:
- 对渲染的纹理提取超出一定亮度的片段,可以使用MRT多渲染目标技术,使用2个颜色纹理附件,在fs中指定两个颜色输出,一个为正常的场景渲染到缓冲1,另一个将超过一定亮度的颜色保留到颜色缓冲2
- 对新的纹理模糊,可以使用高斯模糊
- 两个纹理叠加,颜色相加再转换
延迟渲染
- early_z可以极大减少不必要的fs计算,但由于渲染顺序原因仍有一部分片元进行不必要的fs,当场景有大量光源时,这种性能消耗将变的非常巨大,想象数千个光源对每个通过early_z的片元做计算
- 两个处理阶段(Pass)
- 几何处理阶段(Geometry Pass),fs不做光照计算,获取对象的各种几何信息(片段世界空间的(光照计算在世界空间中) 位置,漫反射纹理颜色,法线,深度……),存储在G缓冲即帧缓冲中,利用MRT技术,所有的数据像素插值结果输出为纹理图像
- 光照处理阶段(Lighting Pass),使用G-buffer输出的纹理,执行光照计算,由于上个pass所有数据都是经过深度测试保留下来的,即最前面片段对应的数据,排除了不必要的光照计算
- 延迟渲染缺陷
- 消耗显存,因为要存储大量几何数据
- 不支持不同的光照算法(blinn_phong,PBR……)
- 不支持半透明物体的颜色混合,颜色混合重要的事情是对物体排序,以便后面的物体更新的颜色,和前面的物体混合,但Pass2时仅有最前面的片段数据,后面片段被丢弃掉了没办法混合,本质就是缺少数据,我们解决这个问题将这些数据保留,但消耗的内存是庞大的
- 不支持抗锯齿,采样法的抗锯齿涵盖在光栅化所有阶段,每个采样点的数据需要保留到下个pass,如果用SSAA内存消耗是巨大的,如果用MSAA,依旧要大量消耗内存,每次被图元覆盖都需要对像素着色,以便之后拷贝给对应采样点,可我们只有最顶层的片段,哪些采样点需要做着色计算,计算拷贝给哪些采样点(属于同一图元)……
- 解决缺陷
- 使用不同光照算法的物体使用不同的pass渲染,深度测试需要使用上一次的深度缓冲
- 如果渲染透明物体,需要在延迟渲染后进行正向渲染,因为要先渲染不透明物体,才有可混合的颜色
- 抗锯齿使用FXAA后处理技术
- 延迟渲染 vs 正向渲染
- 延迟渲染不容易支持一些功能
- 在较小场景光源较少时,延迟渲染可能更慢,因为两次pass的消耗,并且有更大的时间和内存消耗
光体积
- 虽然延迟渲染是一个很大的优化,但仍不能支持非常大量的光源, 因为仍然需要为每一个光源n对每一个像素m做光照计算,m*n,这仍是非常庞大的
- 原理:计算光源的半径,只对在光体积内的像素光照计算,不在光体积的片元就不必fs计算
- 技术方案
- 光球体数据准备阶段:依次遍历光源,求半径, 为光创建实际球体,球体中心放在光源位置
- 求半径
- 利用衰减方程,将完全黑暗0颜色带入公式左边,但由于衰减方程永远不会==0,只会趋近于0,所以使用近似黑暗5/256颜色值
- 通过移项形成一元二次方程,可以通过求根公式解
- 求半径
- 几何处理阶段:为场景生成G_Buffer
- 光照处理阶段:渲染每个光球体,光栅化生成球体对应的片元,对这些片元采样G_Buffer的数据fs计算,这样不在光体积内的由于未通过覆盖性测试,不会产生片元,就不会fs
- 如果多个光源重叠,将计算的颜色值混合处理
- 光球体数据准备阶段:依次遍历光源,求半径, 为光创建实际球体,球体中心放在光源位置
本文由作者按照 CC BY 4.0 进行授权