Skip to content
【转载】基于径向模糊的体积光在Cesium中的应用

概述

当空间中包含足够稠密的光散射介质(例如气体分子和气溶胶)时,光源透过遮挡物的缝隙投射的光线打在空气中的尘埃上,产生散射进入到人眼中,这些光线看起来像是一道一道的光柱,被称为体积光。

在图形渲染中,体积光对画面的质感能起到很大的提升作用。体积光的渲染主要有BillBoard贴片径向模糊光线追踪 3 种方式。BillBoard贴片是把带有光柱效果的图片叠放在原始场景之上,实现方式不够灵活,换另一个场景就得另一组图片;径向模糊用后处理方式实现,效果不错,性能开销较小;光线追踪效果最好,算法较为复杂,性能消耗相对也较大。

在以上3种方式中,径向模糊在算法复杂度、性能开销、渲染效果等方面的表现相对均衡,同时它是在后处理阶段实现的,正好 Cesium 提供了一套现成的后处理机制,因此我们不用考虑后处理的基本流程,只要提供片元着色器和相应的 uniform 变量即可。本文主要讨论基于径向模糊算法的体积光及其在Cesium上的实现思路。

图1 体积光效果

径向模糊算法

径向模糊算法的核心思想是:在当前片元到光源的路径上选取一系列的采样点,考虑权重和衰减等因素的影响算出采样颜色,采样颜色之和为当前片元最终的颜色。算法逻辑如图2所示,当前片元径向模糊后的颜色 Color 是所有采样颜色之和,屏幕空间中每个片元都按照这个逻辑计算一次。图3是径向模糊前后对比的示例,可以看出是朝一个方向模糊的,这也是径向的含义。表1是径向模糊的GLSL代码片段,虽然用到了循环,但实际使用中并没有感觉性能受到多大影响。

图2 算法逻辑

图3 径向模糊前后对比

C++
/// Our light scattering pass texture
uniform sampler2D UserMapSampler;
/// Indicate where is the light source on the screen (2D position)
uniform vec2 lightPositionOnScreen;
void main()
{
 float decay=0.96815;
 float exposure=0.2;
 float density=0.926;
 float weight=0.58767;
 /// NUM_SAMPLES will describe the rays quality, you can play with
 int NUM_SAMPLES = 100;
 vec2 tc = gl_TexCoord[0].xy;
 vec2 deltaTexCoord = (tc — lightPositionOnScreen.xy);
 deltaTexCoord *= 1.0 / float(NUM_SAMPLES) * density;
 float illuminationDecay = 1.0;
 vec4 color =texture2D(UserMapSampler, tc.xy)*0.4;
 for(int i=0; i < NUM_SAMPLES ; i++)
 {
    tc -= deltaTexCoord;
    vec4 sample = texture2D(UserMapSampler, tc)*0.4;
    sample *= illuminationDecay * weight;
    color += sample;
    illuminationDecay *= decay;
 }
 gl_FragColor = color;
}

表1 径向模糊 GLSL 代码片段

Cesium中体积光的实现思路

1、在Cesium提供的后处理机制中,我们不用自己去离屏渲染原始场景的纹理,在后处理阶段的片元着色器中可以直接拿到颜色纹理(colorTexture)和纹理坐标(v_textureCoordinates)。

图4 原始场景纹理

2、光源正常渲染,遮挡光源的物体都渲染为黑色,得到一张采样纹理。建议在Cesium中把太阳和大气都作为光源,如果只把太阳作为光源,最后体积光的效果不明显。

图5 光源正常渲染、遮挡物涂黑的纹理

3、把上一步渲染的纹理传给径向模糊的着色器,在这张纹理上采样,逐片元算出径向模糊后的颜色,得到图6所示的径向模糊纹理。

图6 径向模糊纹理

4、把上一步经过径向模糊的纹理和原始纹理叠加就可以看到如图7所示的体积光的效果了。

图7 Cesium中的体积光效果

本文转自 https://blog.csdn.net/2301_79959413/article/details/134965721,如有侵权,请联系删除。

Updated at: