介绍:
体积光,也被称作神光(Godrays)、阳光尘或光束效果(crepuscular rays),是一种视觉效果,经常被用于增强3D渲染图、视频游戏和电影中的自然光照效果。体积光效果通过模拟光线在三维空间中传播时遇到各种障碍(如云、尘埃或水雾等)而产生的散射现象,来产生一种戏剧性和真实感十足的视觉体验。
常用的webgl框架均有实现:
three.js 实现:
babylon 实现:
cesium 实现:
获取一帧只有太阳,径向模糊的画面
获取一帧正常的画面
两个画面融合
附上实现代码:(使用cesium最新的版本1.106) 如有问题可以私信我
第一步:使用后处理,对画面进行径向模糊
javascript
const blurShader = `
uniform sampler2D UserMapSampler;
uniform vec2 lightPositionOnScreen;
uniform float decay;
uniform float exposure;
uniform float density;
uniform float weight;
in vec2 v_textureCoordinates;
bool isSunVisible(vec2 position) {
return position.x > 0.0 && position.x < 1.0 && position.y > 0.0 && position.y < 1.0;
}
void main()
{
vec2 tc = v_textureCoordinates;
int NUM_SAMPLES = 100;
vec2 deltaTexCoord = (tc - lightPositionOnScreen.xy);
deltaTexCoord *= 1.0 / float(NUM_SAMPLES) * density;
float illuminationDecay = 1.0;
vec4 color =texture(UserMapSampler, tc)*0.4;
for(int i=0; i < NUM_SAMPLES ; i++)
{
tc -= deltaTexCoord;
vec4 mysample = texture(UserMapSampler, tc)*0.4;
mysample *= illuminationDecay * weight;
color += mysample;
illuminationDecay *= decay;
}
out_FragColor = vec4(color.rgb * exposure, 1.0);
}
`;
第二步:对遮挡太阳的进行遮挡,得到一个只有阳光的图
javascript
`
#version 300 es
uniform sampler2D passTexture;
uniform sampler2D depthTexture; // 场景深度纹理
uniform bool isSkyAtmosphereVisible; // 大气是否显示
in vec2 v_textureCoordinates; // 来自顶点着色器的纹理坐标
float getDepth(in vec4 depth) {
float z_window = czm_unpackDepth(depth);
z_window = czm_reverseLogDepth(z_window);
float n_range = czm_depthRange.near;
float f_range = czm_depthRange.far;
return (2.0 * z_window - n_range - f_range) / (f_range - n_range);
}
void main() {
vec4 color;
vec4 depthColor = texture(depthTexture, v_textureCoordinates);
float depth = getDepth(depthColor);
if (depth >= 1.0) {
color = texture(passTexture, v_textureCoordinates);
} else {
color = vec4(0.0, 0.0, 0.0, 1.0);
}
out_FragColor = color;
}
`
第三步、对获取到的两张图进行融合
javascript
`
uniform sampler2D baseTexture;
uniform sampler2D blendTexture;
in vec2 v_textureCoordinates;
float blendScreen(float base, float blend) {
return 1.0-((1.0-base)*(1.0-blend));
}
vec3 blendScreen(vec3 base, vec3 blend) {
return vec3(blendScreen(base.r,blend.r),blendScreen(base.g,blend.g),blendScreen(base.b,blend.b));
}
void main()
{
vec4 base = texture(baseTexture, v_textureCoordinates);
vec4 blend = texture(blendTexture, v_textureCoordinates);
vec3 sceneColor = blend.xyz;
sceneColor = czm_RGBToHSB(sceneColor);
if (sceneColor.z > 0.8) {
sceneColor.z -= 0.2; // 降低亮度
// 限制亮度值在0到1之间
sceneColor.z = max(sceneColor.z, 0.0);
}
sceneColor = czm_HSBToRGB(sceneColor);
float opacity = 1.0;
vec3 blendColorDodge = (blendScreen(vec3(base.rgb), sceneColor)) * opacity + vec3((base.rgb) * (1.0 - opacity));
out_FragColor = vec4(blendColorDodge, base.a);
}
`