雾中点光源的简单着色器

我需要一个简单快速的着色器来创建雾,并通过点光源进行照明。为了实现它,我编写了屏幕空间的效果,其结果如下所示。输送机几乎与普通点源一样简单。它不需要数据量结构,光线行进,并且可以轻松连接到现有的照明着色器。

最重要的原理是,您可以以封闭形式计算雾所发出的光,就好像它是由点光源照明的一样。我的解决方案是在着色器中找到公式及其替换。


使用我的技术在雾中渲染飞船的一个小场景

基本设置

雾模型


着色器对我们正在使用的雾作了一些假设。实际上,他认为雾的每个碎片都是小的半透明白色散射表面。

  • 着色器建议雾将光在所有方向均匀散射。真实的雾气或烟雾并不总是具有此属性,但这与我们要拍摄的图片非常吻合。
  • Shader建议所有波长的光以相同的方式与雾交互。实际上,情况往往并非如此。例如,瑞利散射使天蓝色,比其他波长散射的蓝光更多。
  • 雾发出的光根据从光源到雾的距离的平方的平方而变化。实际上,这不会发生,但看起来很正常。有很多资源可以解释雾实际上是如何散射照明的,我相信您可以用这些公式来补充我的方法。

尽管如此。即使使用这些简化方法,结果似乎也是合理的。

分析溶液


让雾无穷小(想象一小块雾)。然后,这片雾在我的系统中发出的光看起来像:

light=1(distance from light to fog fragment)2


该公式表明,与雾到光源的距离成反比的平方,来自雾的每个片段的光都减少了,而来自光散射表面的光就是这种情况。

为了方便起见,我们将等式重写为:

d=distance from light to fog fragment


light=1d2


view linelight atxdx


或者,如果更正式地:

L=light position


w=world fragment position


c=camera position


light arriving at camera=cw1|xL|2dx



该积分恰好表达了我们所需的内容,但是其计算却比我们所需的更为复杂。由于上图中的所有变量都是具有三个值的向量,因此我们基本上必须处理12个变量。我将通过简单的重新参数化消除大多数这些变量。

定义一个称为“ light space的新空间

  • x轴是视线
  • Y轴照明


现在,我不再只是在三维空间中进行线性积分,而是简单地沿X轴执行从摄影机到世界碎片的积分。接下来,我们需要重写积分。距点的距离x光源 x轴上的 xh2+x2因此,视线积分采用以下形式

1h2+x2dx


手动或在您喜欢的计算机代数系统中求解它,我们得到:

1h2+x2dx=tan1(xh)h


也就是说,为了使照明在给定的视线范围内来自雾,我计算了从相机到整个世界的积分。如果相机在x=a,是世界的一个片段x=b,则从照亮的雾沿着视线进入像素的照度具有以下形式:

ab1h2+x2dx=tan1(bh)htan1(ah)h


实施思路


我设法在延迟的着色器管道中实现了该着色器,而无需进行重大修改。为此,有必要添加大约十行GLSL代码。如果传送带已经使用点光源来计算漫反射+镜面反射照明,则点光源着色器应该已经可以访问相机位置。光源和世界上的当前像素,这就是您所需要的!

处理多个光源非常简单。只需简单地总结每个光源的雾散射光的效果即可。为了使该系统对多个光源有效,必须仅对距离光源如此近的像素计算积分,以使其有助于场景中视觉上可见的光量。例如,在延迟的着色器传送带中,可以在光源周围渲染球形网格,以便着色器仅计算该光源附近像素的光效果。

我发现,实现此着色器最困难的部分是相机的正确位置以及照明空间中世界的一部分,因此我们可以使用简化的积分。

结果



用很少的雾灯产生世界低水平


如果有更多来源,效果会更强


如果您还跟踪有关光源方向的信息,则可以在雾中创建精美的图形照明

补充阅读


光散射简介:影像学的观点

实时渲染的实用分析性单散射模型

大气散射和体积雾算法第1部分

All Articles