How God's Eye View Handles Aircraft and Ship Icon Orientation in Cesium.js
God's Eye View orients aircraft and ship icons by projecting world-space heading vectors onto the camera's screen-space basis and applying a 0.5° deadband stabilization to prevent jitter, implemented in src/data/iconOrientation.js and applied to Cesium billboards in the flights and vessels rendering layers.
God's Eye View, an open-source Cesium-based tracking visualization in the bilawalsidhu/gods-eye-view repository, renders real-time aircraft and maritime traffic. Handling aircraft and ship icon orientation requires converting geographic course data into screen-space billboard rotations that remain accurate regardless of camera position or viewing angle.
The Challenge of Camera-Facing Billboards
Cesium billboards are camera-facing quads that always rotate to face the viewer. This makes standard world-space rotation impossible because the icon must appear to point in the direction of travel while remaining perpendicular to the camera's view direction. The solution requires transforming the entity's course vector into screen-space coordinates relative to the current camera orientation.
Screen-Space Projection Pipeline
Converting World Heading to Screen Coordinates
The core logic resides in src/data/iconOrientation.js within the screenProjectedRotation function (lines 52-80). This utility converts a heading in degrees clockwise from north into a stable screen-space rotation angle.
The function projects the world-space forward vector onto the camera's right (camera.rightWC) and up (camera.upWC) vectors. It calculates screen-space components (dx, dy) and derives the rotation angle using Math.atan2(-dx, -dy). This approach ensures the icon points correctly even when the entity is behind the camera or in tracked-orbit mode.
Stabilizing Sub-Degree Rotations
Rapid micro-changes in calculated angles cause visual jitter. The stabilizeScreenRotation function (lines 92-100 of src/data/iconOrientation.js) compares the newly computed angle with the previous frame's rotation. If the angular difference falls below the 0.5° deadband threshold, the function retains the previous rotation value, smoothing out insignificant variations while preserving responsiveness to actual course changes.
Entity-Specific Implementation
Aircraft Icons in flights/rendering.js
For aircraft tracking, the orientation helpers are imported and applied in src/layers/flights/rendering.js at line 1172. Each aircraft billboard's rotation property receives the stabilized screen-projected value, ensuring flight icons align with their ADS-B reported heading.
Ship Icons in vessels/rendering.js
Maritime vessels utilize identical orientation logic in src/layers/vessels/rendering.js at line 199. The system processes AIS-reported courses through the same projection pipeline, allowing ship icons to point along their actual track regardless of the map's current perspective.
Icon Assets and Visual Reference
The actual SVG silhouettes rendered as billboards are defined in src/data/aircraftIcons.js (lines 15-19). These nose-up white glyphs—including airliner, widebody, and turboprop variants—are rendered as data-URI billboards. The rotation calculated by the orientation pipeline is applied to these assets, making the icons appear to point in the direction of travel.
Practical Implementation Example
// Pattern used in src/layers/flights/rendering.js
import { screenProjectedRotation, stabilizeScreenRotation } from '@/data/iconOrientation';
let previousRotation = null;
// scene: Cesium.Scene, position: Cartesian3, courseDeg: number from ADS-B/AIS
const projected = screenProjectedRotation(scene, position, courseDeg, previousRotation);
const stableRotation = stabilizeScreenRotation(previousRotation, projected);
// Apply to Cesium billboard entity
billboard.rotation = stableRotation;
previousRotation = stableRotation; // Store for next frame's deadband comparison
The same pattern applies to maritime vessels in src/layers/vessels/rendering.js, ensuring consistent orientation behavior across both domain types.
Summary
- Screen-space projection: The
screenProjectedRotationfunction insrc/data/iconOrientation.jsconverts world heading to camera-relative rotation usingcamera.rightWCandcamera.upWCbasis vectors withMath.atan2(-dx, -dy). - Jitter prevention: The
stabilizeScreenRotationfunction applies a 0.5° deadband to suppress sub-degree oscillations while maintaining responsiveness to actual course changes. - Cross-domain usage: Both aircraft (
src/layers/flights/rendering.js) and ships (src/layers/vessels/rendering.js) use identical orientation logic imported from the central utility module. - Asset definition: SVG silhouettes in
src/data/aircraftIcons.jsserve as the visual base for rotated billboards.
Frequently Asked Questions
Why can't billboards be rotated in world space directly?
Cesium billboards are implemented as camera-facing quads that always orient toward the viewer. World-space rotation would cause the icon to appear tilted or edge-on when viewed from certain angles. By projecting the heading vector onto the camera's screen-space basis (rightWC and upWC), the icon remains flat to the viewer while pointing in the correct geographic direction.
What is the default deadband threshold for rotation stabilization?
The default deadband is 0.5 degrees (approximately 0.0087 radians). The stabilizeScreenRotation function compares the new rotation angle against the previous frame's value and suppresses updates below this threshold, preventing visual jitter from minor floating-point variations or sensor noise.
How does the system handle entities behind the camera?
The screen-space projection method using Math.atan2(-dx, -dy) on the camera's right and up vectors produces correct orientation even when entities are behind the camera or in tracked-orbit mode. This ensures icons remain visually consistent regardless of the entity's position relative to the camera frustum.
Where are the aircraft icon graphics defined?
The SVG silhouettes are defined in src/data/aircraftIcons.js (lines 15-19) as data URIs. These include multiple aircraft types (airliner, widebody, turboprop) rendered as nose-up white glyphs that rotate based on the calculated screen-space rotation values applied in the rendering layers.
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 →