OpenGL使用可编程管线实现屏幕空间环境光遮蔽

2018-06-06 10:14易湘舟李永李敏
电脑知识与技术 2018年7期

易湘舟 李永 李敏

摘要:OpenGL计算机图形编程接口实现了计算机对3D图形的渲染功能,然而旧版本的OpenGL(兼容版 compatibility profile)是采用固定管线的渲染模式对图形进行渲染,固定管线中的渲染程序是固定的,OpenGL用户无法更改这类渲染程序,这使得旧版本OpenGL的使用者实现的功能受到了很大的限制。新版本的OpenGL(核心板 core profile)则采用了可编程管线模式对图形进行渲染,可编程管线相对于传统固定管线的优势在于图形该如何和渲染可以由OpenGL用户来实现,从而使OpenGL的灵活性得到扩展。将通过可编程管线来实现传统固定管线难以实现的环境光遮蔽效果。

关键词:OpenGL;可编程渲染管线;屏幕空间环境光遮蔽

中图分类号:TP393 文献标识码:A 文章编号:1009-3044(2018)07-0173-03

OpenGL作为一个成熟而久负盛名的跨平台的计算机图形应用程序接口规范,它已经被广泛用于游戏、影视、军事、航空航天、地理、医学、机械设计,以及各类科学数据可视化的领域[1~3]。目前大部分的研究均基于OpenGL实现[4]。随着时间的推移以及计算机图形学的发展,OpenGL自身也进行了很多的更新换代,在OpenGL3.0中,某些特性被标记为“不鼓励使用的”,也就是说这些特性在未来的OpenGL版本中可能会被删除。而被标记“不鼓励使用的”功能主要目的是推动OpenGL标准的发展[5],所以为了提高程序的规范性和兼容性,开发者有必要了解并使用OpenGL核心模式(core profile)。在核心模式中,开发者可以更灵活的渲染、处理自己的模型以获得更多的效果。

1 系统原理及结构

OpenGL中所有的事物都被放在一个抽象的3D空间之中,然而屏幕只是一个二维的像素阵列,并不是一上来就可以直接显示3D图像的,所以OpenGL的任务是将3D图形从一堆二进制数据的形态转换成能够显示到屏幕上的每一帧图片。而OpenGL的渲染管线先将顶点数据的3D坐标转换为2D坐标让它符合正常人的视觉习惯,然后再根据渲染规则为每个像素染上合适的RGB颜色。

OpenGL管线结构示意图[6]

当调用OpenGL的glDrawArrays()函数之后GPU会根据顶点数组中的坐标数据和指定的模式,对传进来的顶点数据进行一系列的处理,这些处理分别由着色器和一些硬件固定操作完成,其中着色器(Shader)是一类可编程的程序模块,在OpenGL中它由程序员使用类似于C语言的GLSL(OpenGL Shader Language)来完成,我们可以通过shader来告诉显卡该怎么渲染目标顶点所构成的3D图形。现代的GPU具备了很强的可编程性,用户可以通过编写高级着色程序控制渲染管线中的各个模块,极大扩展了GPU的功能,将原来由CPU承担的运算迁移到GPU完成[7]。

2 屏幕空间环境光遮蔽问题的分析与解决方案的实现

2.1 屏幕空间环境光遮蔽的预期目标

经典而又常见的三种光照模:Lambert,Phong,BlinnPhong都使用了理想的环境光,然而环境光主要是用来描述从空气中散射到物体上的光线的,因此理想的环境光照忽略了当两个或多个面上的像素相距非常近时的情形,这种情形下两个或多个面上的像素会相互遮挡散射过来的光线从而导致该面的局部反射的光线要少于理想模型下的光照所反射的光线。所以为了提高所渲染的物体的真实程度,必须对被遮挡的部分进行加深处理。

解决这个问题可以从模型的贴图着手,在模型被建立出来后模型师会对模型的UV贴图进行烘焙处理,这个过程就是一种静态的处理环境光遮蔽的方式,然而这种方式也有它的弊端:第一,当模型绑定了骨骼之后,模型的动作会产生变化导致遮蔽位置的变更,或者与其他物体相靠近后对比效果会存在差异;第二,纹理贴图加载的时间会变得更长。但从渲染效果方面考虑的话,前者的影响会变得更大。未开启AO(Ambient Occlusion环境光遮蔽)特效的画面光照稍亮一些;而开启AO特效之后,局部的细节画面尤其是暗部阴影会更加明显一些[8]。

因此为了提高效果,我们必须得从渲染环节着手动态解决这个问题。也就是利用OpenGL可编程管线来解决这个问题,使每一帧输出图像都具有环境光遮蔽的效果而且该效果不会受到模型的变化所带来的影响。

2.2 屏幕空间环境光遮蔽的原理

2.2.1 延迟渲染

与延迟渲染相对应的是正向渲染,在顶点数据(包括顶点的位置数据以及法向量数据)被送入处顶点着色器之后,正向渲染会计算出所有面的被光照后的颜色包括最终会被深度测试裁剪掉的面也会被渲染上颜色,这样就产生了不必要的计算。而延迟渲染的原理则是先让顶点数据过一遍管线,剔除掉最终无法显示到屏幕上的面,然后输出到G-Buffer,G-Buffer上一般包含了将渲染的每一片段的位置信息(Position)法向量(Normal vector)和深度信息(Depth),再将G-buffer中的信息送入管线让着色器对其进行处理。此法可提高渲染效率避免计算被遮蔽的面。但缺陷是不便于处理透明物体。

有了G-buffer中的可见三维空间信息,我们就可以利用GPU来处理我们的图像,经过多重pass,最后混融并渲染到我们的屏幕上。

第一遍pass经过片段着色器后输出以下纹理到帧缓冲区:

其中:

图2展示了第一个纹理,即每个片段的位置信息(gPosition);

图3展示了第二个纹理,即每个片段的法向量信息(gNormal);

圖4展示了第三个纹理,即每个片段的深度信息(gDepth)。

2.2.2 环境光遮蔽采样

为了使被遮蔽的面上产生阴影,首先应该获取每一片段的信息并对其周围半球内是否有面遮挡进行随机采样,根据采样的结果来削弱该片段的环境光反射分量,将样本核心通过矩阵变换沿着法向量的方向布置在片段上,计算每个样本的深度使之与G-buffer中的深度比较,如果样本值小于G-buffer中的深度且它们之间的距离不太远,则说明该样本被遮蔽了。由于采用的是G-buffer中的深度数据进行采样,所以被丢弃的不可见片段无法参与采样。这使得在多个边缘的交界处的遮蔽分量比正向渲染得到的要少一点,从而在细微的视觉效果上产生缺失。为了方便我们只用rgb中的r值(红色),r值越低,表示遮蔽因子越大,看起来越黑。

输入纹理:

经过采样后片段着色器输出得到纹理:

2.2.3 模糊化

计算出遮蔽分量后其效果如果所示,显然如果直接运用,阴影效果会显得非常生硬,这时我们需要将我们的环境光遮蔽效果使用均值模糊将其模糊化,让它看起来更加柔和自然。

输入纹理:

得到纹理:

2.2.4 添加光照

根据第一遍pass得到的gPosition,gNormal,gDepth和光源位置和亮度计算每一个片段的rgb颜色值。

其中,漫反射光照亮度的計算需要与第三遍pass得到的纹理的r值(遮蔽因子)相乘。

每一片段的颜色(FragColor) =环境光光照 (Ambient) +漫反射光光照 (Diffuse) +镜面反射光光照 (Specular)

其中环境光光照需额外乘遮蔽因子。

3 ssao实现前后的效果

4 结语

通过可编程管线操控GPU并行处理3D图形程序早已成为图形编程的主流固定管线的,即使OpenGL开发团队也对以前的一些旧特性进行了限制不鼓励开发者使用。使用可编程管线可以实现原来固定管线难以实现的功能,比如SSAO屏幕空间环境光遮蔽技术,先通过帧缓冲存储片段信息,然后再利用可编程管线中的片段着色器对帧缓冲中的信息进行采样,根据被遮蔽的样本量来决定片段的遮蔽分量,再通过均值模糊让阴影显得更加柔和,最终使用可编程管线渲染最后的图像。相比传统固定管线,可编程渲染管线大大提高了程序的灵活性,可以实现固定管线几乎无法实现的功能。

参考文献:

[1]Dave Shreiner, Graham Sellers, John Kessenich,等.OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 4.3 Eight Edition[M].王锐,译.北京:机械工业出版社,2014.

[2]詹发新.地形可视化的进展与评述[J].四川测绘,2004(2).

[3]高武俊,张继贤,张永红.基于OpenGL的地形3维可视化研究[J].测绘通报,2002(S1).

[4]刘浩,赵文吉,段福洲,等.基于GPU的地下管线三维可视化建模研究[J].计算机工程与应用,2013(8).

[5]Richard S.Wright.Jr, Nicholas Haemel, Graham Sellers,等.OpenGL SuperBible Fifth Edition[M].付飞,李艳辉,译.北京;人民邮电出版社,2012.5.

[6] Khronos OpenGL4.4PiplineMap

[7] 刘磊,冯前进,王文辉,等. 基于GPU的医学图像快速面绘制[J]. 计算机工程与应用,2007,43(32):189-191.

[8] 杨志成.一种改进的屏幕空间环境光遮蔽(SSAO)算法[J].现代计算机,2017(8).