体积光渲染技术

简介: 遮光物体被光源照射时,在其周围呈现的光的放射性泄露,称其为体积光。例如太阳照到树上,会从树叶的缝隙中透过形成光柱。之所以称之为体积光,是因为这种特效下的光照相比以往游戏中的光照给人视觉上以空间的感觉。体积光让游戏玩家更真实的感觉。

什么是体积光

遮光物体被光源照射时,在其周围呈现的光的放射性泄露,称其为体积光。例如太阳照到树上,会从树叶的缝隙中透过形成光柱。之所以称之为体积光,是因为这种特效下的光照相比以往游戏中的光照给人视觉上以空间的感觉。体积光让游戏玩家更真实的感觉。有时也指实现这一特效的技术。-《百度百科》

Volumetric lighting is a technique used in 3D computer graphics to add lighting effects to a rendered scene. It allows the viewer to see beams of light shining through the environment; seeing sunbeams streaming through an open window is an example of volumetric lighting, also known as crepuscular rays. The term seems to have been introduced from cinematography and is now widely applied to 3D modelling and rendering especially in the field of 3D gaming. -《Wikipedia-Volumetric lighting》

下图是我读书的时候在学校里面拍的体积光示意图。
1

游戏中的体积光效果

2
3

上面两张是从《辐射4》中截取的体积光示意图(来自Nvidia),而谈到体积光,不得不说的是一款很著名的独立游戏《inside》。这款游戏利用体积光(当然还有雾,glow等其他技术),把阴暗的氛围烘托得十分出色,是体积光应用的一个极好的例子。
4
5

基于Billboard的体积光

基于Billboard的体积光很简单,就是生成一个明暗条纹,加上一个遮罩图,再贴到两个或者若干个交叠的面片上即可。

6

这种方式比较简单,效果也还过得去。尤其是用于远景的体积光表示是很合适的。但是对于近景,尤其是观察角度比较自由的情况下就容易穿帮。

基于后处理的体积光

基于后处理的体积光渲染比较像Bloom,只不过做模糊的方法有点不一样。后处理实现体积光的方法流程为:

  1. 渲染出整个画面
  2. 提取画面中高亮的部部分(参数控制)
  3. 对高亮部分进行径向模糊(注意,bloom用的一般不是径向模糊)
  4. 将径向模糊后的高亮层和原图进行叠加

这个方法的效果不错,消耗也不大,而且效果可以独立控制,只是针对光源不在画面内的情况没办法处理。另外,体积光的那种颗粒感和不均匀的线条感很难得到。如果改用更复杂的后处理算法的话,消耗会增加得比较厉害。

而Unreal中采用bloom method渲染的体积光也是基于这个思路。

9

基于Occlusion的体积光

这种方案也是unreal采用了的一种方法,具体做法是:

  1. 从场景的深度图创建一张mask(参数控制阈值)
  2. 沿着光源射出去的方向,blur这张mask图
  3. 用blur后的mask图来mask场景中的雾效和大气效果

这个方法解决了后处理方案中,当光源不在画面中无法得到正确效果的问题。但是这个方法的问题是,体积光的效果取决于当前场景中的大气和雾效。下图是采用Occlusion渲染的体积光的一张示意图。

10

Ray-Marching和基于Ray-Marching的体积光渲染

作为基础知识,首先介绍一下Ray-Marching。

重要的放前面,要详细了解Ray-Marching可以阅读这篇博客 Ray Marching and Signed Distance Functions

简单来说,Ray-Marching主要是用于体绘制的一种方案,类似于Ray-Tracing,从观察者的位置向屏幕的每个点发射一条射线,每次步进一定的距离,直到到达物体表面,然后再进行光照计算。由于Ray-Marching步进的过程,可以进一步计算得到观察者和目标物体之间的光照结果,因而对于体绘制有特殊的帮助。关于Ray-Marching就先讲这么多。

有了Ray-Marching的基本概念,在pixel shader中我们可以模拟Ray-Marching的做法,绘制体积光。

11

  1. 从起点开始,沿着射线每次推进一点,采样每个点的亮度,所有经过的采样点上的散射亮度求和就是像素的颜色
  2. 散射光的亮度和离光源的距离成平方反比
  3. 迭代介质中的光散射亮度

这种做法,往往需要迭代几十次,因此消耗很大,而后有人利用线积分的解析公式替代迭代计算,本文就不具体推导公式了。

这种做法得出的效果有一些问题,比如各个方向上散射光强度一样,没有变化,不够真实,另外这种体积光也不会被遮挡。

因此,我们在计算散射光强度的时候,不应该只由到光源的距离来衰减光强,还应该乘以以下几个因子:

  1. 散射因子(HG公式), HG公式表示了每个方向散射出去的光线亮度应该是不一样的,并且散射出去的光线亮度总合应该和射到尘埃上的那束光线亮度一样,也就是能量守恒。公式内容可以自行google。
  2. 投光比因子:根据Beer-Lambert法子,根据物质的密度和到光源距离,可以描述入射光强度和透光强度的比值。
  3. 阴影因子:类似ShadowMapping等阴影算法,略去不详述。

经此计算后的体积光,有了更多的变化,也更加真实了。

13

Epipolar Sampling Based Light Shafts

对于基于Ray-Marching渲染体积光的方案,有很多改进的算法,本文介绍一种基于极坐标的方案。

改进算法的目标是比较一致的,就是想减少采样次数,从而减少计算复杂度。而基于极坐标采样的方案就是源自一个观察结果:体积光中光线的散射强度沿着光源射出去的线,变化是不大的;而在这些一条条射出去的射线之间,散射光强度是有明显变化的。

由此想到了从光源到屏幕边缘固定的一些点连线,只用Ray-Marching计算这些连线上某些点的散射光强度,再利用插值的方法计算其他点的散射光强度,并存在一张贴图中。最后在渲染场景的时候,从贴图中采样散射光的强度,并合成到画面上。

极坐标采样示意图如下。

14

极坐标采样的步骤是:

  1. 从光源到屏幕坐标连线,决定采样点在屏幕空间的位置;
  2. 在depth不连续的地方,补充采样点;
  3. 利用Ray-Marching计算散射光强度,并利用插值计算剩下点的散射光强度;

最后,渲染场景,再从记录了散射光强度的texture中插值采样即可。更具体的算法可以参考 IVB Atmospheric Light Scattering 和Epipolar Sampling for Shadows and Crepuscular Rays in Participating Media with Single Scattering 这篇文章。

这种算法的效果图如下:

15
16

相关文章
|
6月前
|
缓存 编解码 JavaScript
在JavaScript小游戏开发中,如何优化游戏性能,比如减少重绘、提高动画流畅度?
提升JavaScript游戏性能的关键点包括:使用requestAnimationFrame优化动画流畅度;减少DOM操作,利用DocumentFragment或虚拟DOM;使用Canvas/WebGL高效渲染;优化图像资源,压缩图片和使用雪碧图;分层渲染与视口裁剪减少无效绘制;借助Web Workers进行后台计算;缓存计算结果;合理添加事件监听器并采用事件委托;定期进行性能分析以找到并解决瓶颈。不断测试与调整是优化的关键。
104 4
|
存储 编解码 计算机视觉
使用ffmpeg缩小视频体积的几种方式
上述命令将输入视频input.mp4转换为H.265编码格式,并将结果保存为output.mp4文件。其中,-c:v选项表示视频编码器,libx265表示使用x265编码器,-crf选项表示视频质量,28表示目标视频质量,值越小视频质量越高,文件体积越大。
363 0
|
1月前
|
编解码 算法 测试技术
在不影响动画质量的前提下对 Lottie 动画文件进行压缩
【10月更文挑战第16天】在不影响动画质量的前提下对 Lottie 动画文件进行压缩需要综合运用多种方法和策略。通过细致的分析、合理的调整和适当的技术手段,可以在保持动画视觉效果的同时,有效地减小文件的大小,提升动画的性能和用户体验。
81 1
|
6月前
|
存储 缓存 监控
深入理解前端性能优化:从网络到渲染
网络优化包括减少HTTP请求、使用HTTP/2、开启GZIP压缩和缓存策略。资源加载优化涉及懒加载、预加载和预读取。渲染优化建议使用Critical CSS、减少CSS和JavaScript阻塞以及避免强制同步布局。Service Worker实现离线存储,性能监控使用Lighthouse等工具。动态导入和代码拆分减少初始加载时间,响应式图片适应不同设备。Web Workers处理耗时任务,避免内存泄漏。
91 3
|
6月前
|
Web App开发 前端开发 JavaScript
只需一行CSS代码,让长列表网页的渲染性能提升几倍以上!
只需一行CSS代码,让长列表网页的渲染性能提升几倍以上!
|
6月前
|
缓存 前端开发 算法
前端需要加载一个大体积的文件时,可以这么优化
前端需要加载一个大体积的文件时,可以这么优化
|
6月前
|
缓存 自然语言处理 前端开发
JS/CSS体积减少了67%,我们是如何做到的?
JS/CSS体积减少了67%,我们是如何做到的?
61 1
|
6月前
解决Vue3.0项目多次运行后,项目体积增大问题(高达60G)
解决Vue3.0项目多次运行后,项目体积增大问题(高达60G)
177 0
|
编解码 缓存 图形学
unity中的渲染优化技术
unity中的渲染优化技术
|
存储 缓存 算法
OpenGL图像渲染以及渲染问题解决方案
在绘制3D场景的时候,我们需要决定哪些部分是对观察者可见的,或者哪些部分是对观察者不可见的,对于不可见的部分,应该及早丢弃。例如在一个不透明的墙壁后,就不应该有渲染,这种情况叫做隐藏面消除(Hidden surface elimination).
624 0
OpenGL图像渲染以及渲染问题解决方案