How the Gods-Eye-View Icon Orientation System Handles Horizon Culling
The icon orientation system combines a binary EllipsoidalOccluder for geometric culling with a continuous sky-backdrop blend factor to smoothly fade entity icons when they fall below the visible horizon.
The bilawalsidhu/gods-eye-view repository implements a robust horizon culling mechanism in src/data/iconOrientation.js that prevents flight, vessel, and camera icons from rendering when occluded by the Earth's curvature. This icon orientation system handles horizon culling through two complementary mathematical techniques that balance performance efficiency with visual smoothness.
The Dual-Mechanism Architecture
The implementation relies on two coordinated techniques defined in src/data/iconOrientation.js. These mechanisms operate sequentially during each render tick to determine visibility and aesthetic blending.
Horizon Occluder for Binary Culling
At the core of the system is a reusable Cesium.EllipsoidalOccluder instance that performs rapid point-inclusion testing against the WGS84 ellipsoid. According to the source code in lines 26-29, the horizonOccluder(camera) function refreshes this singleton with the current camera position each frame:
export function horizonOccluder(camera) {
_occluder.cameraPosition = camera.positionWC; // ← update camera pose
return _occluder;
}
The occluder's isPointVisible(pos) method tests whether a billboard's world position lies behind the planet relative to the camera viewpoint. Because the application uses Google 3D Tiles instead of the default Cesium globe, the depth buffer lacks information for the far side of the Earth. The EllipsoidalOccluder mathematically determines occlusion without depth queries, returning a boolean that immediately culls geometry below the horizon.
Sky-Backdrop Factor for Smooth Transitions
While the occluder provides hard culling, the skyBackdropFactor function (lines 70-115) implements a soft fade band that prevents icons from popping at the horizon boundary. This function calculates a continuous blend value based on angular displacement from the horizon line:
export function skyBackdropFactor(cameraPosition, position, featherRad = HORIZON_FEATHER_RAD) {
/* … geometry calculations … */
const horizonHalfAngle = Math.asin(Math.min(1, 1 / cameraMag));
const margin = rayAngle - horizonHalfAngle;
const t = Math.min(1, Math.max(0, margin / (2 * featherRad) + 0.5));
return t * t * (3 - 2 * t); // smoothstep blend
}
The function accepts a featherRad parameter defaulting to approximately 0.019 radians (1.1°), defining the transition zone width. Values below the horizon return 0 (ground-background), values above return 1 (sky-background), and the smoothstep interpolation (t * t * (3 - 2 * t)) ensures perceptually smooth alpha blending across the feather region.
Practical Implementation in the Rendering Pipeline
Consumer modules integrate these utilities by updating the occluder state each frame and applying visibility tests to billboard entities. The following pattern from src/data/flights.js demonstrates the standard integration:
// Example: Culling a flight billboard each frame
function updateBillboard(billboard, scene) {
const cam = scene.camera;
const occluder = horizonOccluder(cam); // ← refresh occluder
const visible = occluder.isPointVisible(billboard.position);
billboard.show = visible; // hide if below horizon
// Optional: apply a sky-fade for labels attached to the billboard
const blend = skyBackdropFactor(cam.positionWC, billboard.position);
billboard.labelMaterial.alpha = blend; // 0 → fully ground, 1 → fully sky
}
For stationary icons requiring orientation logic alongside culling, such as those in src/data/cctv.js, the system combines rotation stabilization with the same horizon tests:
import { screenProjectedRotation, stabilizeScreenRotation } from './iconOrientation.js';
const rotation = screenProjectedRotation(scene, iconPos, courseDeg);
icon.billboard.rotation = stabilizeScreenRotation(icon.prevRotation, rotation);
Integration Across the Codebase
The horizon culling logic extends beyond aviation entities. While src/data/flights.js applies these methods to commercial flight billboards, src/data/militaryFlights.js implements Nadir-stable icon orientation using the identical horizonOccluder logic for military assets. Similarly, src/data/cctv.js employs the occluder for camera-plane orientation calculations, ensuring CCTV monitor planes only render when geometrically visible above the horizon curve.
Summary
- The icon orientation system in
src/data/iconOrientation.jsfuses binary geometric culling with smooth alpha blending to handle horizon visibility for moving entities. - The Horizon Occluder utilizes a
Cesium.EllipsoidalOccluderupdated per-frame viahorizonOccluder(camera)to mathematically test point visibility against the Earth's ellipsoid (lines 26-29). - The Sky-Backdrop Factor provides a continuous
smoothstepblend across a 1.1° feather radius to eliminate popping artifacts near the horizon boundary (lines 70-115). - Production modules including
src/data/flights.js,src/data/militaryFlights.js, andsrc/data/cctv.jsconsume these utilities to ensure icons render only when geometrically appropriate.
Frequently Asked Questions
How does the horizon occluder handle the lack of depth buffer information for the far side of the globe?
Because Gods-Eye-View uses Google 3D Tiles instead of the default Cesium globe, the depth buffer does not contain depth information for the far side of the Earth. The Cesium.EllipsoidalOccluder mathematically calculates whether a point lies behind the planet's silhouette from the camera's perspective using the WGS84 ellipsoid model, eliminating the need for depth-based occlusion queries.
What is the purpose of the feather radius parameter in skyBackdropFactor?
The featherRad parameter defaults to approximately 0.019 radians (1.1°) and defines the angular width of the transition band around the horizon. This creates a smooth fade effect where icons gradually blend between ground and sky backgrounds rather than instantly popping visible or invisible, which improves visual coherence during camera movement.
Why does the sky-backdrop factor use smoothstep interpolation instead of linear blending?
The function returns t * t * (3 - 2 * t), which is a standard smoothstep curve. This interpolation method provides zero derivatives at the endpoints, creating a visually smooth acceleration and deceleration of the blend factor that appears more natural to human perception than linear interpolation, which would create noticeable velocity changes at the transition boundaries.
Where is the horizon culling logic applied in the codebase?
The primary implementation resides in src/data/iconOrientation.js, but the horizonOccluder function is consumed by multiple entity modules including src/data/flights.js for commercial aviation tracking, src/data/militaryFlights.js for military asset visualization, and src/data/cctv.js for camera surveillance plane orientation.
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 →