五步实现向OpenGL ES延迟光照系统添加光线追踪

发表于2016-08-17
评论0 3.5k浏览


  为了能够在交互式帧率情况下实现图像渲染,所使用的引擎必须近似真实世界的一些现象---例如阴影----而不是简单的模拟。随着实施渲染技术不断向前发展,实现这些功能的成本也在不断降低。尽管从传统的角度来看像是一个复杂的离线处理过程,但是受益于可见的周围物体,光线追踪正成为一个越来越可行的选择。
  谈到我们的PowerVR 光线追踪硬件平台,基于分布的延迟渲染光栅化功能与负责光线追踪的模块单元练习紧密,这就给我们提供了一种选择,作为光栅化渲染的一种补充,而不是直接取代。在这篇文章中,我将向大家介绍如何向OpenGL ES延迟光照系统添加光线追踪功能。

延迟光照+光线追踪
  G-buffer混合渲染是我们在大部分光线追踪实例中所采用的技术,因为事实证明它可以充分利用我们的PowerVR 光线追踪硬件平台。GPU的光栅轨迹用于在屏幕上渲染对象数据。这些信息用于初始化第二次的光线,然后传输给硬件平台来实现。通过每个像素使用更少的光线,应用程序就可以合理安排光线预算,以便在后期管道最需要的时候。
  当然这种方法还有一个更大个好处——它还可以多加利用已经生成G-buffers的延迟光照系统!
  下面是向一个基于OpenGL ES的延迟光照系统添加光线追踪功能的五大步骤:

第一步:更新场景层次结构(光线追踪)
  与光栅化渲染不同的是,在光线追踪API中不提供绘制函数调用。因此每一帧的图像渲染是将光线发射到场景层次加速结构中,其中包含了世界空间内所有对象物体数据信息。如果层次结构内的对象数据不需要改变,那么每一帧的渲染我们可以重复使用场景层次,但是当有些组件需要修改时,那么在光线追踪渲染前相应的场景层次必须要重新搭建。

光线追踪流程——场景层次结构生成

  除此之外一下条目描述了如何进行任务分工:
  条目 描述
  构件  一个3D对象以及相关的材料属性(例如缓存(buffers)和着色器)
  构件组 场景加速结构用于高效的光线盒子和光线三角形测试,由众多构件或者构建组组合而成
  场景阵列  构建组处理阵列,光线必须传递给阵列中一个元素
  当构建组搭建完成后,输入组件就会经过顶点着色程序处理,从而转换为世界空间。转换数据会传递给固定功能的场景结构生成器单元来生成场景结构。值得注意的是构件组会建立无效的场景内容,因此每次建立都需要传入满足要求的构件列表。
  尽可能重用的是在每次启动时那些不需要改变的构建组可以被创建,例如建筑物和地形。额外的构建组则是需要在每帧修改后生成。为了避免流水线阻塞,动态构建组可以采用多个缓冲这样光线可以覆盖整个层次结构,同时另一个应用程序则开始搭建另一个构建组。搭建完成后,在光线调整之前所有构建组可以被合并。

动态和静态构建组

  一个典型的包含动态对象的应用程序,下面几步必须要执行:
1、更新动态构件
  必要的时候修改属性和缓存设置
2、搭建动态构建组
  选择动态“缓冲区”,完成构件序列的搭建
3、合并构件组
  光线调整之前需要合并最新的动态和静态构建组
  显示的同步操作。在合并的API调用和光线追踪渲染结束期间构建组是不能被修改的。
  搭建工作完成后,应用程序就需要执行下一个任务。

第二步:搭建G-buffer(光栅化)
  在这一步中,GPU的光栅化流水线用于渲染屏幕空间对象数据生成G-buffer。信息的存储依赖输入,这些事光照和光线追踪通路所要求的,通常包括世界空间坐标系内的位置、法线、材料ID和反照率。

搭建G-buffer

  与光线追踪不同,光栅化流水线需要对象的每一帧先被转换到摄像机视角空间中。一个应用程序必须提交所有对象的调用包括视觉约束体,从而完成G-buffer的渲染。
  因为PowerVR是基于分布的结构,参考显卡驱动暴露出EXT_shader_pixel_local_storage选项扩展,G-buffer数据可以保存在片上,因此可以不用执行带宽密集型结构的写和读操作。这些操作就降低了延迟和功率消耗。

第三步:延迟光照(光栅化)
  一旦完成了G-buffer的渲染操作,就可以计算屏幕空间的光照。为了避免片外写这些数据,可以写入到本地像素存储空间,然后帧着色器就可以读取。

 
混合G-buffer光照

第四步:发射主光线和计算光线——对象交互(光线追踪)
  步骤4a:发射主光线(光线追踪)
  条目
  描述
  帧着色器
  发射主光线的着色阶段。帧着色器实例执行应用程序定义的宽x高元素

利用G-buffer数据初始化光线

  在OpenGL ES光线追踪API中,光线的发射依赖帧着色器。在G-buffer混合渲染器中,帧着色器会执行每个G-buffer像素。存储在G-buffer中的对象数据就可以用来初始化像素光线。
  内置的gl_SceneMG功能允许帧着色器实例指定哪一个场景阵列元素的光线将会被呈现。在动态更新的场景中,光线必须发送给最新合并的动态+静态构件组。
  与计算着色一样,帧着色器也不要求有输出。它们可以选择将数据写入缓存和图像,同时重要的是它们也可以反射光线。
  扩展包括一个新的图像增加功能和一个限定符标记统一图像变量,仅实现累加功能。这些特性允许使能硬件帧累加器缓存来优化图像的写操作。
  步骤4b:光线——对象交互(光线追踪)
  条目 描述
  光线着色器  原始的光线交互会执行光线着色操作,光线着色可以与某个构件绑定

光线——光照交互

  光线一旦发送出来将会遍布整个场景结构,然后执行光线盒子和光线三角形交互测试。当光线三角形交互发生时,绑定相关交互对象的光线着色器就会执行。光线着色器可以访问光线数据,例如原始点坐标和方向,以及用户自定义的光线数据。同样也可以访问未插入的数据,例如纹理坐标和法线。差值函数会提供交互重心坐标,让用户完全控制差值操作是如何执行的。与帧着色器相似,光线着色器没有要求输出,可以选择写入缓存、图像或者渲染累加器缓存,它们也可以选择发射更多的光线。

第五步:后期处理(光栅化)
  光线追踪渲染完成后,后期处理可以用于过滤渲染后的图像,并且应用常规的三维空间效果(模糊运动、深度视野、图案装饰等)。

总结

通用的G-Buffer混合渲染流水线

  借助G-buffer混合渲染,OpenGL ES延迟光照系统可以受益于光线追踪效果。在后面的文章中我们将详细介绍这个技术是如何用于指定的光线追踪效果增强渲染的,例如屏幕空间柔和阴影。如果你有任何疑问,请在下方留言。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引