How to Load Google Photorealistic 3D Tiles in CesiumJS: A Complete Implementation Guide
To load Google Photorealistic 3D Tiles in CesiumJS, set Cesium.GoogleMaps.defaultApiKey to your Google Maps API key, call Cesium.createGooglePhotorealistic3DTileset() with onlyUsingWithGoogleGeocoder: true, add the returned tileset to viewer.scene.primitives, and hide the default globe by setting viewer.scene.globe.show to false.
Google Photorealistic 3D Tiles provide high-resolution, street-level 3D basemaps that serve as drop-in replacements for Cesium's default globe terrain. In the bilawalsidhu/gods-eye-view repository, the loading logic lives in src/mapStartup.js, which demonstrates production-ready patterns for API key management, automatic fallback handling, and seamless viewer integration when you load Google Photorealistic 3D Tiles in CesiumJS.
Prerequisites: API Keys and Tokens
Before initializing the tileset, you must configure authentication credentials. The implementation supports two routes: direct access via Google Maps Platform or fallback access through Cesium Ion.
- Google Maps API Key: Required for direct access to Google's tile servers. Set this to
Cesium.GoogleMaps.defaultApiKeybefore creating the tileset. - Cesium Ion Token: Optional fallback token. If the direct Google request fails, the loader attempts to fetch the tileset through Cesium's hosted endpoint using
Cesium.Ion.defaultAccessToken.
Loading the Tileset: The Core Implementation
The src/mapStartup.js file exports the loadPhotorealisticTileset function, which orchestrates the entire loading sequence with graceful degradation.
The loadPhotorealisticTileset Function
This asynchronous function attempts to create the tileset in priority order: direct Google access first, then Cesium Ion hosting, and finally a keyless OpenStreetMap globe. It accepts a Cesium instance and an options object containing googleApiKey and cesiumToken.
// src/mapStartup.js – core loader
export async function loadPhotorealisticTileset(
Cesium,
{ googleApiKey = '', cesiumToken = '' } = {}
) {
const googleKey = clean(googleApiKey);
const ionToken = clean(cesiumToken);
const errors = [];
// If we have an Ion token, make it the default for Cesium Ion requests
if (ionToken) Cesium.Ion.defaultAccessToken = ionToken;
// Build the list of possible routes (direct Google → Ion → fallback)
const attempts = [];
if (googleKey) attempts.push({ route: 'google-direct', googleKey });
if (ionToken) attempts.push({ route: 'google-ion', googleKey: undefined });
// Try each route in order
for (const attempt of attempts) {
Cesium.GoogleMaps.defaultApiKey = attempt.googleKey;
try {
const tileset = await Cesium.createGooglePhotorealistic3DTileset({
onlyUsingWithGoogleGeocoder: true,
});
return { tileset, route: attempt.route, errors };
} catch (e) {
errors.push(e instanceof Error ? e : new Error(String(e)));
}
}
// All attempts failed – clean up and fall back
Cesium.GoogleMaps.defaultApiKey = undefined;
return { tileset: null, route: 'osm', errors };
}
Key implementation details from the source code:
- API Key Injection: The function assigns
Cesium.GoogleMaps.defaultApiKeyimmediately before each attempt to ensure the correct credentials are used for each route. - Geocoder Declaration: The
onlyUsingWithGoogleGeocoder: trueoption tells the tileset that the application will use Google's geocoder for coordinate lookups, which is required for proper integration. - Error Aggregation: Failed attempts are captured in an
errorsarray and returned to the caller for debugging without crashing the application.
Integrating with the Cesium Viewer
Once loadPhotorealisticTileset returns a tileset, you must add it to the scene and adjust the viewer configuration to prevent visual conflicts with the default globe.
Adding the Tileset and Hiding the Default Globe
In src/main.js, the initialization code checks the loader result and updates the viewer accordingly. The Google tileset provides its own terrain and imagery, so the native Cesium globe must be disabled.
import { loadPhotorealisticTileset } from './mapStartup.js';
const photoreal = await loadPhotorealisticTileset(Cesium, {
googleApiKey,
cesiumToken,
});
const tileset = photoreal.tileset;
if (tileset) {
viewer.scene.primitives.add(tileset);
viewer.scene.globe.show = false; // Google tiles provide their own globe
console.info(`[Init] Google 3D Tiles loaded via ${photoreal.route}.`);
} else {
// Fallback UI – key‑less globe
viewer.scene.globe.show = true;
}
Handling Map Stack Controllers
The repository's src/mapStackController.js manages the active map "stack" (Google 3D, Bing, Esri, etc.) and reacts to load success or failure events. This separation of concerns ensures that UI components can respond to tileset state changes without tightly coupling the loader to the interface.
Complete Code Examples
Minimal Standalone Implementation
For projects not using the God's Eye View loader, you can implement the pattern directly in a single HTML file. This example demonstrates the essential API calls without the abstraction layer.
<script src="https://unpkg.com/cesium/Build/Cesium/Cesium.js"></script>
<script>
Cesium.Ion.defaultAccessToken = '<YOUR_ION_TOKEN>'; // optional fallback
Cesium.GoogleMaps.defaultApiKey = '<YOUR_GOOGLE_API_KEY>';
const viewer = new Cesium.Viewer('cesiumContainer', { baseLayer: false });
Cesium.createGooglePhotorealistic3DTileset({
onlyUsingWithGoogleGeocoder: true,
}).then(tileset => {
viewer.scene.primitives.add(tileset);
viewer.scene.globe.show = false;
}).catch(err => console.error('Google 3D Tiles failed:', err));
</script>
<div id="cesiumContainer" style="width:100%;height:100vh;"></div>
Production-Ready Loader from God's Eye View
For robust applications, import the battle-tested loader from src/mapStartup.js and handle the three possible return states (success via Google direct, success via Ion, or complete failure).
import * as Cesium from 'cesium';
import { loadPhotorealisticTileset } from './src/mapStartup.js';
const { tileset, route, errors } = await loadPhotorealisticTileset(Cesium, {
googleApiKey: import.meta.env.GOOGLE_MAPS_API_KEY,
cesiumToken: import.meta.env.CESIUM_ION_TOKEN,
});
if (tileset) {
viewer.scene.primitives.add(tileset);
viewer.scene.globe.show = false;
console.log(`Loaded via ${route}`);
} else {
console.warn('Falling back to key‑less globe', errors);
}
Summary
- Authentication: Set
Cesium.GoogleMaps.defaultApiKeyfor direct access orCesium.Ion.defaultAccessTokenfor hosted fallback before calling the creation method. - Creation: Use
Cesium.createGooglePhotorealistic3DTileset({ onlyUsingWithGoogleGeocoder: true })to instantiate the photorealistic tileset. - Integration: Add the returned tileset to
viewer.scene.primitivesand immediately setviewer.scene.globe.show = falseto avoid rendering conflicts. - Fallback: Implement retry logic that captures errors and falls back to a keyless globe (OpenStreetMap) when both Google direct and Ion routes fail, as demonstrated in
src/mapStartup.js.
Frequently Asked Questions
Do I need both a Google API key and a Cesium Ion token?
No, only the Google Maps API key is required to load Google Photorealistic 3D Tiles in CesiumJS. The Cesium Ion token is optional and serves as a fallback mechanism if the direct Google endpoint fails or if you prefer Cesium's managed hosting. According to the src/mapStartup.js implementation, the loader attempts the direct Google route first, then falls back to Ion only if the first attempt fails.
Why must I hide the default Cesium globe?
You must set viewer.scene.globe.show = false because Google Photorealistic 3D Tiles include their own terrain and imagery. Rendering both the default Cesium globe and the Google tileset simultaneously creates z-fighting and visual artifacts. The src/main.js file in the repository handles this by hiding the globe immediately after successfully adding the tileset to the primitives collection.
What happens if the Google tiles fail to load entirely?
If both the direct Google request and the Cesium Ion fallback fail, the loadPhotorealisticTileset function returns { tileset: null, route: 'osm', errors }. The calling code in src/main.js detects the null tileset and keeps the default globe visible, typically configured with open-source imagery like OpenStreetMap or Esri, ensuring the application remains functional even without Google data.
Can I use the Google geocoder without loading the 3D tiles?
Yes, but you must still provide a Google Maps API key. The onlyUsingWithGoogleGeocoder: true flag specifically tells the tileset that you intend to use Google's geocoder services alongside the 3D tiles. In src/keySetup.js, the repository handles key acquisition and validation separately from the tileset loading logic, allowing you to use Google's location services even if the photorealistic tileset fails to initialize.
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 →