游戏中的Volumetric Rendering

2022-2-20 14:13火龙动漫 101 0

总结下游戏中常见的Volumetric Rendering的实现方法

1. 一些理论知识

快速简要地介绍一些理论知识.

光打到粒子上之后的效果:

当不考虑中间介质时候,摄影机中得到的颜色就是最近的点上出射光的颜色

考虑散射时,情况就比较复杂了:

内散射会使路径上的光增多,外散射会使路径上的光变少.通常情况下,为了计算方便,不考虑多次散射的光.

模拟真实光穿透介质的比例的函数:

不同的散射类型:

Rayleigh散射模型用来描述较小的粒子的散射,比如空气粒子的散射使天空变蓝. Mie散射模型是用来描述较大粒子的散射,比如灰尘.

Phase Function 是用来描述光在不同方向的散射分布的函数,根据能量守恒,光在所有方向散射的和总是1

Henyey–Greenstein Phase Function 是一个经常用来描述Mie散射的Phase Function

2. DepthFog

在每个像素计算的正常颜色基础上,根据距离混合一个雾的颜色.

最常用的三种计算雾强度的公式:

Linear : factor = (end-z)/(end-start)

Exp: factor = exp(-density*z)

Exp2: factor = exp(-(density*z)^2)

unity中的全局雾设置和宏APPLY_FOG就是使用这种方式

早期的Opengl和DirectX甚至提供的类似的API接口(glFog 等),在硬件级别实现雾效.

3. PostProcessing Fog

和Depth Fog基本上是一样的,区别在于PostProcessing 的Fog通过在PostProcessing时根据depth texture反推计算出摄影机到目标像素点的距离.

除了用距离做参数,还可以根据高度作为参数,或者高度*距离这样的形式来作为参数.

4. 粒子/BillBoard

在需要雾效的位置使用大量的粒子或者BillBoard来模拟光散射效果或者雾效.很显然,这种方式很可能造成一些OverDraw性能问题,以及需要特定的观察角度,而且不能随光照变化.

5. Sun Shaft

也叫God Ray,通过PostProcessing来实现.GPU Gems 3 13.3中详细描述了这种方法的实现.

原理是进行一次后处理,将游戏界面内的太阳作为中心,向外做一次径向模糊 + Bloom,在朝着太阳光附近观察时,有非常明显的散射效果。由于是直接从屏幕空间取颜色,这种方式需要很亮的 sun disk。

另外一种 SunShaft模式是Occlusion模式,和上面提到的Bloom模式类似,只是在Occlusion模式下,假设空间内的物体都是经过了光散射渲染的,这样就可以通过拉伸遮挡物,实现遮挡雾和天空大气的效果。

UE4中的Light Shafts包含了这两种模式。

Unity早期的Image Effects中,也有Sun Shaft效果组件.

6. RayMarching

使用PostProcessing和RayMarching来实现,GPU PRO5里有一篇文章Volumetric Light Effects in Killzone Shadow Fall by Nathan Vos详细介绍了这种方法.

基本原理是在pre-z得到场景Depth Buffer以及光照的Shadow Map后,确定一个要进行Volume Light的区域(点光源球形,锥形光锥形,直线光是全屏的),RayMarching计算出一个Volume Light的Buffer,计算光照效果时应用效果.

生成Volume Rendering Buffer的过程其实就是在Volume Redering区域中进行RayMarching,为了降低Artfict,通常会使用一个Dither Texture进行抖动,并且在最后对结果进行Blur,得到平滑的结果.

有一个Unity的Volume Lighting的Demo是这种方式来实现的, https://github.com/SlightlyMad/VolumetricLights.

7. Volume Texture

使用Volume Texture来保存空间中的散射信息,是真正意义上的Volume Rendering.

一个详细描述了实现方法的文章: https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite.

一个简单的Volume Texture实现的Volume Rendering的过程:

1.划分VolumeTexture的区域,这里将摄影机视锥内的部分作为Volume Texture区域,沿着垂直于摄影机方向的平面切分.为了较好的性能,将3DTexture的大小弄的小一点,比如180x60x64.

2.渲染光源的Depth Map,为了减少大量PCF阴影的性能消耗,这里用ESM阴影,并进行DownSample.

3.使用Computer Shader,向Volume Texture中写入空间中点的光照信息,光照包含空间环境光,光源光照,求和后写入到Texture RGB通道中.空间点的散射强度值,写入到Texture A通道中.

4.使用Computer Shader,从摄影机方向向外进行RayMarching,使用前面提到的模拟散射穿透计算的公式,累加光照.

5.渲染某个点时,在VolumeTexture中查找相应点的散射光照值,进行计算.

详细的实现解析可参考:TC130:体渲染探秘(二)基于VoxelVolume实现体积雾

现代的PC游戏,大多会使用这种方式来实现体积雾效果,已经成了大型游戏的标配。不过由于精度限制,这种方式一般只能支持大约200m内的雾效。


鲜花

握手

雷人

路过

鸡蛋

最新评论

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-4-23 21:49 , Processed in 0.072768 second(s), 18 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.