Mastering WebGL Bloom: From Framebuffers to HDR Post‑Processing

This guide explains how to overcome large‑scale 3D map visualization challenges by using off‑screen rendering, framebuffers, and a step‑by‑step Bloom effect implementation—including bright‑area extraction, Gaussian blur, image merging, and HDR integration—in WebGL.

Baidu Maps Tech Team
Baidu Maps Tech Team
Baidu Maps Tech Team
Mastering WebGL Bloom: From Framebuffers to HDR Post‑Processing

1. Business and Technical Pain Points

In large‑scale 3D map visualizations, especially with massive geographic data, two main issues arise: the sheer data volume makes it hard to highlight key areas, and the visual effect often looks flat, unrealistic, and unexciting.

2. Framebuffer and Off‑Screen Rendering

To achieve post‑processing effects you must understand off‑screen rendering. Normally rendering goes directly to the default framebuffer created with the window. Off‑screen rendering creates one or more additional framebuffers (FBOs) and renders the scene to a texture, allowing further processing.

WebGL provides gl.createFramebuffer() to create an FBO and gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer) to bind it for rendering. After processing, binding gl.bindFramebuffer(gl.FRAMEBUFFER, null) returns rendering to the default framebuffer.

3. Simple Post‑Processing Example

As a basic demonstration, invert the colors of a rendered scene by sampling the screen texture and computing 1.0 - color in the fragment shader:

void main() {
    FragColor = vec4(vec3(1.0 - texture(Sampler2D, TexCoords)), 1.0);
}

This single line flips the colors, creating a striking effect.

4. Bloom (Glare) Effect

Bloom highlights very bright colors that exceed the normal RGB range (0‑255). By extracting bright regions, blurring them, and adding the result back to the original image, objects appear to emit a realistic glow.

5. Step‑by‑Step Bloom Implementation

5.1 Prepare FBOs

gl.bindFramebuffer(gl.FRAMEBUFFER, buffer1); // step1
gl.bindFramebuffer(gl.FRAMEBUFFER, buffer2); // step2
gl.bindFramebuffer(gl.FRAMEBUFFER, buffer1); // step3

5.2 Extract Bright Areas

float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
if (brightness > threshold) {
    color = lightColor;
} else {
    color = vec4(0.0);
}

5.3 Gaussian Blur

vec2 offset = vec2(blurSize / canvasSize.x, blurSize / canvasSize.y);
vec4 result = texture2D(uSampler, vTextureCoord) * weight[0];
if (isVertical) {
    for (int i = 1; i < 10; ++i) {
        result += texture2D(uSampler, vTextureCoord + vec2(0.0, offset.y * float(i))) * weight[i];
        result += texture2D(uSampler, vTextureCoord - vec2(0.0, offset.y * float(i))) * weight[i];
    }
} else {
    for (int i = 1; i < 10; ++i) {
        result += texture2D(uSampler, vTextureCoord + vec2(offset.x * float(i), 0.0)) * weight[i];
        result += texture2D(uSampler, vTextureCoord - vec2(offset.x * float(i), 0.0)) * weight[i];
    }
}
gl_FragColor = result;

5.4 Combine Images

vec4 color = texture2D(originalTexture, vTextureCoord);
vec4 bloomColor = texture2D(bloomTexture, vTextureCoord);
color += bloomColor;

gl_FragColor = color;

5.5 HDR Boost

Bloom works even better with HDR. By using a floating‑point color format such as gl.RGBA16F for the framebuffer, colors can exceed the [0,1] range. After merging, tone‑mapping (e.g., Reinhard or exposure mapping) converts HDR values back to LDR for display.

6. Other Applications

In geospatial big‑data analysis, Bloom can highlight densely populated areas, making crowd clusters instantly visible.

GraphicsWebGLShaderHDRPostProcessingBloomFramebuffer
Baidu Maps Tech Team
Written by

Baidu Maps Tech Team

Want to see the Baidu Maps team's technical insights, learn how top engineers tackle tough problems, or join the team? Follow the Baidu Maps Tech Team to get the answers you need.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.