How GLSL Post‑FX Effects Power Sensor Simulations in God’s Eye View
God’s Eye View implements sensor simulations by attaching GLSL fragment shaders as Cesium PostProcessStage objects to the scene graph, manipulating the rendered color texture through uniforms to generate NVG, FLIR, CRT, and other visual effects in real time.
God’s Eye View is an open-source geospatial visualization project that renders immersive sensor simulations—including night vision, thermal imaging, and retro CRT modes—using Cesium JS. The system achieves these cinematic looks by injecting custom GLSL post‑fx effects into the rendering pipeline, processing the final framebuffer after the 3D world draws but before it reaches the screen.
Shader Module Architecture
Each visual style ships as a self‑contained GLSL module exposing uniforms and a fragment shader entry point. The codebase defines distinct shaders such as retroShader, nightVisionShader, thermalShader, animeShader, noirShader, and snowShader in dedicated style files.
For example, the CRT retro simulation in src/styles/retro.js implements pixelation, scan‑lines, and distortion effects. Every module follows a consistent pattern: they sample the rendered color texture, apply algorithmic transformations based on uniform values, and write the result to out_FragColor. Key uniforms include intensity, pixelation, and distortion, which the UI controls update at runtime.
Cesium Post‑Process Integration
The central orchestration happens in src/ui.js (lines 3052–3276), where the application constructs Cesium.PostProcessStage instances and registers them with the scene pipeline.
// ui.js – adding a stage to the Cesium pipeline
this.viewer.scene.postProcessStages.add(stage);
// bloom & sharpen stages are cached for later intensity tweaks
this._bloomStage = this.viewer.scene.postProcessStages.bloom;
this.viewer.scene.postProcessStages.add(this._sharpenStage);
The controller caches references to expensive effects like bloom and sharpen, enabling real‑time intensity adjustments without reconstructing the stage objects.
Activating Sensor Modes
Mode switching is handled by CockpitViewController.setVisionMode in src/ui.js. When a user selects a sensor—such as “NVG” for night vision or “FLIR” for thermal—the controller normalizes the input, swaps the active style, and triggers a cross‑fade transition lasting TRANSITION_DURATION_MS = 500 milliseconds.
setVisionMode(mode, { revealParameters = false } = {}) {
const next = normalizeCockpitVisionMode(mode);
this.visionMode = next;
// … UI updates …
this.onVisionChange?.(next, this.active, { revealParameters });
}
The normalizeCockpitVisionMode helper and mode definitions reside in src/cockpitVisionPolicy.js, which enumerates supported COCKPIT_VISION_MODES and their associated shader mappings.
Uniform Management and Intensity Mapping
Effect intensity travels from UI controls to GPU uniforms through a mapping layer in src/bloom.js. Helper functions like bloomStrengthFromIntensity convert percentage values (0–200) into Cesium‑native bloom parameters.
The shader modules read the intensity uniform to drive visual impact—modulating pixelation severity, scan‑line opacity, color channel separation, or thermal gradient contrast. This decoupling allows the rendering engine to remain agnostic of UI implementation while the post‑process stages react to uniform updates every frame.
Detection Overlay Rendering
Sensor simulations must preserve detection call‑outs and targeting markers. The detection system in src/data/detection.js draws overlays on a separate “sensor lane” that blends with the post‑processed output. This ensures that threat markers and sensor call‑outs appear correctly warped and color‑graded alongside the simulated imagery, maintaining situational awareness even under heavy visual distortion.
Practical Implementation Examples
Switching to Night‑Vision (NVG)
// Assume `viewer` is a Cesium Viewer instance
const cockpit = new CockpitViewController(viewer, {
onVisionChange: (mode) => console.log('Vision mode →', mode),
});
// User presses the “NVG” button – change the vision mode
cockpit.setVisionMode('surveillance'); // “surveillance” = NVG style
Adding a Custom GLSL Post‑Process Stage
import { Cesium } from 'cesium';
// Simple grayscale shader
const grayStage = new Cesium.PostProcessStage({
name: 'gray',
fragmentShader: `
uniform sampler2D colorTexture;
in vec2 v_textureCoordinates;
void main() {
vec4 col = texture(colorTexture, v_textureCoordinates);
float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114));
out_FragColor = vec4(gray, gray, gray, col.a);
}
`,
uniforms: {}
});
// Insert into the pipeline (after existing stages)
viewer.scene.postProcessStages.add(grayStage);
Adjusting Bloom Intensity via UI Control
// UI slider returns a value 0‑200 (percent)
function onBloomSlider(percent) {
const intensity = bloomStrengthFromIntensity(percent);
cockpit._bloomStage.enabled = intensity > 0;
cockpit._bloomStage.strength = intensity;
}
Summary
- GLSL post‑fx effects are packaged as modular shader files (e.g.,
src/styles/retro.js) that expose uniforms for real‑time parameter adjustment. - Cesium.PostProcessStage objects wrap these shaders and attach to
viewer.scene.postProcessStages, executing after the main 3D render. - CockpitViewController.setVisionMode manages sensor switching with a 500 ms cross‑fade transition defined by
TRANSITION_DURATION_MS. - Uniform mapping in
src/bloom.jsbridges UI percentages to GPU‑compatible intensity values. - Detection overlays in
src/data/detection.jsrender on a separate compositing lane to ensure markers remain visible under distortion effects.
Frequently Asked Questions
How do I add a custom sensor simulation shader to God’s Eye View?
Create a new GLSL fragment shader module that samples colorTexture and writes to out_FragColor, then instantiate a Cesium.PostProcessStage with your shader source and add it via viewer.scene.postProcessStages.add(). Register the mode in src/cockpitVisionPolicy.js and wire the activation through CockpitViewController.setVisionMode.
What is the transition duration between vision modes?
The default cross‑fade duration is 500 milliseconds, defined by the constant TRANSITION_DURATION_MS in src/ui.js. This value controls the smooth interpolation when switching between NVG, FLIR, CRT, or other sensor simulations.
How does bloom intensity translate to Cesium rendering parameters?
The src/bloom.js module provides bloomStrengthFromIntensity(), which maps UI percentage values (typically 0–200) to Cesium’s internal bloom strength scalar. The cached this._bloomStage receives these values through its strength property, while the enabled boolean toggles the effect entirely.
Where are the GLSL shader uniforms defined for sensor effects?
Uniforms are declared within each style module (such as src/styles/retro.js) and bound to the Cesium.PostProcessStage constructor’s uniforms object. The CockpitViewController updates these uniforms—particularly intensity—at runtime to reflect cockpit control inputs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →